如何从tableView的行中的类访问所有属性值

问题描述

我是使用第一个应用程序的全新快速编码器。

我有两个单独的数组-1包含一个类的所有属性名称,另一个数组包含这些属性的所有值。

这两个数组用于填充tableView(1列UILabel,另一列为textView),以便每一行代表该类的1个属性

我希望能够编辑每一行中的值并将其保存到CoreData。

当前,我有一个switch命令和基于case path.row值的个别case语句,可让应用确定正在编辑哪个textview及其对应的属性

但是,如果我有很多属性来针对所有这些选项提供单独的案例,这将非常麻烦-取决于我选择拥有的属性,它可能是几十个。

我以为我可以做类似的事情:

   propertyArray = ["name","Sex",Type"]
   valueArray = [self.animal.name,self.animal.sex,self.animal.type]  

   for x in (1...3) (the 3 being the total number of properties)

     switch indexPath.row

         case x

            self.animal.(propertyArray[x]) = textView.text

很显然,我这里没有使用所有完整的语法-只是让您了解我的逻辑。但是最后一条语句中的语法根本不起作用,因为系统会在句点之后查找实际的属性名称,并且无法接受看起来似乎不是的替代变量。

关于如何执行此操作的任何建议?

解决方法

您可以做的是使您的类符合Encodable,这将使您可以将其序列化为JSON对象。更简单地说,假设对象上没有大量属性,则可以创建一个函数,以[String:Any]的形式返回属性名称及其值的字典。

所以,您的课程看起来像这样:

class Animal {
    var name: String
    var sex: Sex
    var type: Type

    init(name: String,sex: Sex,type: Type) {
        self.name = name
        self.sex  = sex
        self.type = type
    }

    func toDict() -> [String: Any] {
        return [
            "name": self.name,"sex": self.sex,"type": self.type
        ]
    }
}

当我们有了对象的字典表示形式时,我们可以轻松地分别通过Array(self.animal.toDict().keys)Array(self.animal.toDict().values)将字典的键和值都转换为数组。因此,在您的UITableView中,您可以执行以下操作:

class SomeViewController: UIViewController {

    @IBOutlet var tableView: UITableView!
    var animal: Animal

    init(animal: Animal) {
        self.animal = animal
    }

    override func viewDidLoad() {

        super.viewDidLoad()
        tableView.delegate = self
        tableView.dataSource = self
    }
}

extension SomeViewController: UITableViewDelegate,UITableViewDataSource {
    override func tableView(_ tableView: UITableView,numberOfRowsInSection section: Int) -> Int {
        let propertyNames = Array(self.animal.toDict().keys)
        return propertyNames.count
    }

    override func tableView(_ tableView: UITableView,cellForRowAt indexPath: IndexPath) -> UITableViewCell {

       let cell = tableView.dequeueReusableCell(withIdentifier: "propertyCell",for: indexPath) as! PropertyCell

        let propertyName = Array(self.animal.toDict().keys)[indexPath.row]
        cell.propertyNameTextView.text = propertyName

        let propertyValue = Array(self.animal.toDict().values)[indexPath.row]
        let propertyValueString: String!
        if (propertyValue is String) {
            propertyValueString = propertyValue
        } else {
            //The following would require your Sex and Type enums to have associated values of the String type
            if let sex = propertyValue as? Sex {
                propertyValueString = sex.rawValue
            } else if let type = propertyValue as? Type {
                propertyValueString = type.rawValue
            }
        }
        cell.propertyValueTextView.text = propertyValueString
       
        return cell
    }
}

P.S。抱歉,如果此代码似乎有点不对劲。我最近在Dart中做了很多编程工作,而不是在Swift中做更多的事情:)

,

您可能需要对反射进行一些研究:

let mirror = Mirror(reflecting: classInstance)

这是一个非常简单的示例,可能会有所帮助:

class MyClass: UIView {
    var myColor: UIColor = .blue
    var myName: String = "MyName"
    var myAge: Int = 21
    var myPoint: CGPoint = CGPoint(x: 100,y: 200)
}

class ExampleViewController: UIViewController {
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        let myClass = MyClass()

        // list the properties,types and values
        listProperties(for: myClass)

        // change some values
        myClass.myColor = .red
        myClass.myName = "You know who I am"
        myClass.myAge = 42
        myClass.myPoint = CGPoint(x: 50,y: 50)
        
        print()
        print("Properties after changes:")
        print()

        // list the properties,types and values
        listProperties(for: myClass)
        
    }

    func listProperties(for classInstance: Any) -> Void {

        let mirror = Mirror(reflecting: classInstance)
        
        for child in mirror.children {
            print("Property name: ",child.label)
            print("Property type: ",type(of: child.value))
            print("Property value:",child.value)
            print()
        }

    }
    
}

调试控制台输出:

Property name:  Optional("myColor")
Property type:  UICachedDeviceRGBColor
Property value: UIExtendedSRGBColorSpace 0 0 1 1

Property name:  Optional("myName")
Property type:  String
Property value: MyName

Property name:  Optional("myAge")
Property type:  Int
Property value: 21

Property name:  Optional("myPoint")
Property type:  CGPoint
Property value: (100.0,200.0)


Properties after changes:

Property name:  Optional("myColor")
Property type:  UICachedDeviceRGBColor
Property value: UIExtendedSRGBColorSpace 1 0 0 1

Property name:  Optional("myName")
Property type:  String
Property value: You know who I am

Property name:  Optional("myAge")
Property type:  Int
Property value: 42

Property name:  Optional("myPoint")
Property type:  CGPoint
Property value: (50.0,50.0)