问题描述
我有两个单独的数组-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)