【问题标题】:Dynamically create objects and set attributes in swift快速动态创建对象并设置属性
【发布时间】:2015-06-30 18:42:20
【问题描述】:

我正在研究一个自定义场景,其中我需要在运行时创建一个已定义类的对象并为其设置属性。在objective-C中是这样的

//The Model class

@interface Car:NSObject
{
  @property(nonatomic,copy) NSString * numberOfDoors;
  @property(nonatomic,copy) NSString * carModel;
  @property(nonatomic,copy) NSString * carMake;
  @property(nonatomic,copy) NSString * carBrand;

}

为上述类创建一个自定义运行时对象(不确定这是否正确,但只是从我的脑海中说出来)

id myNewObject =  [[NSClassFromString(@"Car") alloc]init];
[myNewObject setValue:@"4 doors" forKeyPath:@"numberOfDoors"];
[myNewObject setValue:@"Prius" forKeyPath:@"carModel"];
[myNewObject setValue:@"2014" forKeyPath:@"carMake"];
[myNewObject setValue:@"Toyota" forKeyPath:@"carBrand"];

所以我的意图是创建一个对象映射模块,该模块将采用类名和一个对象映射信息,该信息将描述如何从 JSON 响应映射/创建模型对象(非常类似于 RestKit 减去核心数据同步部分)。

我知道这可以用 Objective C 来完成,但不确定这如何适用于 swift 类

感谢任何帮助。

【问题讨论】:

  • 我是 swift 新手,但据我所知它是强类型的,所以可能无法仅在运行时确定对象的类型。
  • @Levi 是的,我也有同感,但在我看到的某个线程中的某个地方动态创建对象是可能的,但不确定设置属性。
  • 你是说属性吗? Swift 根本不支持自定义属性。您只能使用 Apple 提供的属性(如 @objc)。如果您的意思是属性,那么您需要更新您的答案,因为属性和属性是两个非常不同的东西。
  • 所以只要使用RestKit,它不需要你使用Core Data
  • @Wain 不,我不想使用 RestKit,我想自己做点什么。

标签: ios swift


【解决方案1】:

我认为这就是你想要的:

@objc(MyClass)
class MyClass : NSObject {
    var someProperty = 0
}

let type = NSClassFromString("MyClass") as! NSObject.Type
let instance = type()
instance.setValue(12, forKey: "someProperty")

【讨论】:

    【解决方案2】:

    我想出了这个(大)示例:

    class Car {
        // using static constants for quick refactoring (if you want)
        static let numberOfDoors = "numberOfDoors"
        static let carModel = "carModel"
        static let carMake = "carMake"
        static let carBrand = "carBrand"
    
        // dictionary for storing the values
        var properties = [
            Car.numberOfDoors : "",
            Car.carModel : "",
            Car.carMake : "",
            Car.carBrand : ""
        ]
    
        // computed properties to easily access the values
        // you probably don't need the setter
        var numberOfDoors: String {
            get{ return properties[Car.numberOfDoors]! }
            set{ properties[Car.numberOfDoors] = newValue }
        }
        var carModel: String {
            get{ return properties[Car.carModel]! }
            set{ properties[Car.carModel] = newValue }
        }
        var carMake: String {
            get{ return properties[Car.carMake]! }
            set{ properties[Car.carMake] = newValue }
        }
        var carBrand: String {
            get{ return properties[Car.carBrand]! }
            set{ properties[Car.carBrand] = newValue }
        }
    }
    

    所以最后你可能只需要这样的东西:

    class Car {
    
        var properties = [
            "numberOfDoors" : "",
            "carModel" : "",
            "carMake" : "",
            "carBrand" : ""
        ]
    
        var numberOfDoors: String {
            return properties["numberOfDoors"]!
        }
        var carModel: String {
            return properties["carModel"]!
        }
        var carMake: String {
            return properties["carMake"]!
        }
        var carBrand: String {
            return properties["carBrand"]!
        }
    }
    

    正如您所见,Swift 示例比您的 Objective-C 代码更复杂且更容易出错。所以你真的应该考虑使用更静态的行为而不是动态的行为。

    【讨论】:

    • +1 但我最终会将我的响应参数存储在我认为我不想做的类中,并且我想动态设置属性并且无论什么都应该访问属性字典它是模型类。
    【解决方案3】:

    另一种解决方案是让 Swift 类成为 NSObject 的子类:

    class Car : NSObject {
        var numberOfDoors = ""
        var carModel = ""
        var carMake = ""
        var carBrand = ""
    }
    
    let myNewObject =  Car()
    myNewObject.setValue("4 doors", forKey: "numberOfDoors")
    myNewObject.setValue("Prius", forKey: "carModel")
    myNewObject.setValue("2014", forKey: "carMake")
    myNewObject.setValue("Toyota", forKey: "carBrand")
    

    但正如我之前所说,您确实应该考虑使其更加静态,以避免来自拼写错误和复制粘贴代码的错误。

    【讨论】: