CCannot use instance member.... エラー error while creating table view

Asked 2 years ago, Updated 2 years ago, 76 views

While creating a table view that displays the date and cell check items in the section, the tableData definition displays the error Cannot use instance member'checkListItem1' with in property initializer; property initializers run before 'self' is available.How can we solve this problem?Thank you from the bottom of my heart for your reply.

import UIKit

    classViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {

  ////
    func numberOfSections (intableView: UITableView) - > Int // Default is 1 if not implemented
    { return sectionTitle.count
    }
 ////
    functableView(_tableView:UITableView, titleForHeaderInSection section: Int) - > String?// fixed font style.use custom view(UILabel) if you want something different
    {
        return sectionTitle [section]
    }


    // Place the calendar or date picker on the height of the status bar.
    let statusBarHeight=UIApplication.shared.statusBarFrame.height+200

    // Section Items
    var sectionTitle= ["H28,01,23", "H27,12,31", "H28,01,12", "H28,02,21", "H28,11,10" ]


    // Checklist Items and Check Status
    varcheckListItem1: String:Bool = [
        "Item 1": true,
        Item 2 : false,
        "Item 3": true,
        "Item 4": true,
        "Item 5": false
    ]
    varcheckListItem2: String:Bool = [
        "Item 2-1": false,
        "Item 2-2": true,
        "Item 2-3": true,
        "Item 2-4": true,
        "Item 2-5": false
    ]
    varcheckListItem3: String:Bool = [
        "Item 3-1": true,
        "Item 3-2": true,
        "Item 3-3": true,
        "Item 3-4": true,
        "Item 3-5": false
    ]
    varcheckListItem4: String:Bool = [
        "Item 4-1": true,
        "Item 4-2": false,
        "Item 4-3": true,
        "Item 4-4": false,
        "Item 4-5": false
    ]
    varcheckListItem5: String:Bool = [
        "Item 5-1": true,
        "Item 5-2": false,
        "Item 5-3": true,
        "Item 5-4": true,
        "Item 5-5": true
    ]
    variableData=[checkListItem1, checkListItem2, checkListItem3, checkListItem4, checkListItem5]

    lettableView=UITableView()

    override func viewDidLoad(){
        super.viewDidLoad()

        // Creating a UITableView
        tableView.frame = CGRect(
            x —0,
            y —statusBarHeight,
            width —self.view.frame.width,
            height —self.view.frame.height-statusBarHeight
        )
        tableView.delegate=self
        tableView.dataSource=self
        self.view.addSubview(tableView)
    }

    // Creating Cells
    //
    functableView(_tableView:UITableView, cellForRowAtindexPath:IndexPath) - >UITableViewCell{

        // Obtain an array of Dictionary keys
        varkeys = String (tableData.keys)

        // Sort by key
        keys.sort()

        // Retrieve key string
        letcellText=keys [indexPath.row]

        // Cell Creation and Text Configuration
        letcell=UITableViewCell (style:.default, reuseIdentifier: "cell")
        cell.textLabel?.text=cellText

        ///
        let sectionData=tableData[(indexPath as NSIndexPath).section]
        letcellData=sectionData[(indexPath as NSIndexPath).row]



        // If the check state is true, go to the check state from the beginning.
        if self.tableData[cellText]!{
            cell.imageView?.image=UIImage(named: "checked")
        } else{
            cell.imageView?.image=UIImage(named: "unchecked")
        }

        return cell
    }

    // What to do when a cell is tapped?
    functableView(_tableView:UITableView, didSelectRowAtindexPath:IndexPath){

        iflet cell=tableView.cellForRow(at:indexPath){

            // Get text for tapped cells
            letcellText=cell.textLabel?.text

            // Switch Images and Change Dictionary Values
            ifcell.imageView?.image==UIImage(named: "checked"){

                self.tableData.updateValue(false, forKey:cellText!)
                cell.imageView?.image=UIImage(named: "unchecked")
            } else{

                self.tableData.updateValue(true, forKey:cellText!)
                cell.imageView?.image=UIImage(named: "checked")
            }

            // Unselect state
            cell.isSelected=false
        }
    }

    //    functableView(_tableView:UITableView, heightForRowAtindexPath:IndexPath)->CGFloat{
    //        return56
    //    }
    ///
    functableView(_tableView:UITableView, numberOfRowsInSection section:Int) - > Int{
        let sectionData=tableData[section]
        return self.tableData.count
    }    
}

swift swift3

2022-09-30 21:21

1 Answers

Simply put, Swift cannot use other instance variables (all references to self) in the initialization expression for instance properties.

Causes Swift language specific circumstances

For more information, see The Swift Programming Language (Swift 3.0.1)) in the I need you to read this carefully, but since it's long English, the Swift (class) initializer must do the following in the order specified:

Give initial value to all instance properties introduced in your class

(You can give the property an initialization expression or substitute it within your own init)

Call the designated superclass initializer among initializers

(If you inherit the initializer, it will automatically call you, or you can explicitly call it super.init(...) in your initializer.)

So far, other object-oriented languages have similar rules, but Swift has even more stringent restrictions here.

  • You must not access self until you have completed 1.2. above

It's supposed to be thatTherefore, any initialization expression evaluated prior to the initializer cannot use other instance properties (accessed via self) or call instance methods.

(By the way, 1.2. above is supposed to be phase one of the "two-phase initialization" in Swift terminology.)

Workarounds

Therefore, if you want to initialize with a value that uses other instance property values (or uses the results of the instance method), you can do the following:

Give value after reading super.init(...) in your initializer

Due to the above circumstances, super.init(...) cannot be called, so you can give temporary values such as initialization expressions (you may need to set the data type of the variable to Implicitly Unwrapped Optional) and rewrite it after super.init(...).

For ViewController, which usually does not define its own initializer like your code, this pattern can be difficult to use because defining the initializer is troublesome.Reopening and initializing in viewDidLoad() is a very common pattern.

Use the lazy variable

The exception to the above constraints is that lazy declared instance properties can contain other instance properties in the initialization expression.lazy property initialization must remain uninitialized before super.init(...) is first referenced.

Makes the referenced property either a class constant or a top-level constant

Class properties and top-level variables and constants can be used as the initialization of instance properties in class definitions without any problems because they were initialized before the initializer of the class was called.

For your code

If you want to use viewDidLoad() in 1.tableData property declaration is

 variableData: [[String:Bool]]=[ ]

Keep as shown in

override func viewDidLoad(){
    super.viewDidLoad()
    tableData=[checkListItem1, checkListItem2, checkListItem3, checkListItem4, checkListItem5]

    // Creating a UITableView
    tableView.frame = CGRect(
        x —0,
        y —statusBarHeight,
        width —self.view.frame.width,
        height —self.view.frame.height-statusBarHeight
    )
    tableView.delegate=self
    tableView.dataSource=self
    self.view.addSubview(tableView)
}

Will it look like this?

If you use lazy in 2, this is the one line to rewrite.

lazy variableData: [[String:Bool]] = [self.checkListItem1, self.checkListItem2, self.checkListItem3, self.checkListItem4, self.checkListItem5]

It is understandable that self is required to reference each property, considering that the initialization expression of the lazy property is actually a type of closure, but it is difficult to understand the error message when you forget to add self..Check it out yourself.

You can also rewrite the pattern in 3. checkListItem1~checkListItem5 is kicked out of the class to make it the top level constant.

// Checklist Items and Check States
private let checkListItem1: [String:Bool] = [
    "Item 1": true,
    Item 2 : false,
    "Item 3": true,
    "Item 4": true,
    "Item 5": false
]
private let checkListItem2: [String:Bool] ]
    //...
]
private let checkListItem3: String:Bool = [
    //...
]
private let checkListItem4: [String:Bool] = [
    //...
]
private let checkListItem5: [String:Bool] ]
    //...
]
classViewController:UIViewController {

    //...

    variableData=[checkListItem1, checkListItem2, checkListItem3, checkListItem4, checkListItem5]

    //...
}

The Bool value, which represents the check state, is rewritten, so you may not think it can be a let constant, but Swift has both Array and Dictionary values, so tableData has checkListItem1~ checkListI/code> initial value.There is no problem with .You do not want to fiddle with the ViewController instance properties from another class.

More

The sure and easy way is the first one.Try it.

So, if you solve the error in the title, it seems that the error hidden in your code appears in a potato-zuru style, but it's a different matter, so if there's anything you can't solve by yourself, you should ask another question.


2022-09-30 21:21

If you have any answers or tips


© 2024 OneMinuteCode. All rights reserved.