【问题标题】:How can I declare a variable in Swift using the type defined in an AnyClass object?如何使用 AnyClass 对象中定义的类型在 Swift 中声明变量?
【发布时间】:2014-08-21 23:34:19
【问题描述】:

在我的旧 Obj-C 代码中,我可以声明一个字典,其值是其他类的 Class 类型

NSMutableDictionary *Methods = [[NSMutableDictionary alloc] init];
[Methods setObject:[AuthReturnValue class] forKey:@"Authenticate"];
[Methods setObject:[MyOptions class] forKey:@"GetOptions"];

稍后,根据密钥,我可以将 Class 分配给另一个变量

(在标题中)

Class returnType;

(在实现中):

returnType = (Class)[Methods objectForKey:methodName];

然后我可以使用这个 Class 变量来声明一个相同类型的新变量(在这种情况下,它使用 JSONModel 并使用来自其他地方的 NSDictionary 对其进行初始化)

id<NSObject> result;
result = [[returnType alloc] initWithDictionary:(NSDictionary *)responseObject error:NULL];

这很好也很方便,因为 JSONModel 实现了initWithDictionary,这意味着我可以通过这种方式拉入Class,而无需实例化特定类型。

我不知道如何在 Swift 中做到这一点。

例如,这不起作用:

var result: self.returnType.self()
var result: AnyClass = self.returnType.self

还有几十个变种。

如何在 Swift 中将变量声明为在 AnyClass 对象中定义的 class?还是我做错了?

【问题讨论】:

    标签: objective-c swift type-conversion jsonmodel


    【解决方案1】:

    据我所知,您无法实例化 AnyClass。您必须将其转换为更具体的类型。此外,您要使用其元类型实例化的类型必须具有必需的初始化程序。如果我理解你的例子,AuthReturnValueMyOptions 都是JSONModel 的子类,init(responseObject:error:) 初始化器。然后每个子类都必须要求并实现该初始化程序。

    class JSONModel {
        required init(responseObject: NSDictionary, error: NSError?) {
    
        }
    }
    
    class AuthReturnValue : JSONModel {
        required init(responseObject: NSDictionary, error: NSError?) {
            super.init(responseObject: responseObject, error: error)
        }
    }
    
    class MyOptions : JSONModel {
        required init(responseObject: NSDictionary, error: NSError?) {
            super.init(responseObject: responseObject, error: error)
        }
    }
    

    现在你可以这样做了:

    var methods = [String : JSONModel.Type]()
    methods["Authenticate"] = AuthReturnValue.self
    methods["GetOptions"] = MyOptions.self
    if let returnType = methods["Authenticate"] {
        let result = returnType(responseObject: NSDictionary(), error: nil)
    }
    

    更新:

    上面的代码在原生 Swift 类中运行良好,但如果与 Objective-C 类的子类一起使用,当前会崩溃(Xcode6-Beta6)。解决方法是将元类型值存储在 [String : Any.Type] 字典中并在使用前向下转换。以下示例显示了如何使用 NSOperation 的子类来执行此操作。

    class SomeOperation : NSOperation {
    
    }
    
    var dictionary = [String : Any.Type]()
    dictionary["some operation"] = SomeOperation.self
    
    if let aClass = dictionary["some operation"] as? NSOperation.Type {
        // Any initializer available in the superclass can be used for
        // creating instances. The compiler will not perform any checks,
        // as it does with native Swift classes, so we must ensure that subclasses
        // actually implement those initializers, either by automatically inheriting
        // or overriding.
        let test = aClass() 
        println(NSStringFromClass(test.dynamicType))
    }
    

    【讨论】:

    • 这看起来可能是正确的方向,但我在“让结果”行上得到了 EXC_BAD_ACCESS (EXC_I386_GPFLT)。即使我尝试使用没有参数的 returnType 构造函数。仍在研究,但还没有运气。
    • 在 Beta6 中为我工作。你用过完全相同的代码吗?如果方法字典不是 [String : JSONModel.Type],我也会得到 EXC_BAD_ACCESS。它不适用于 NSDictionary、[NSObject : AnyObject]、[NSObject : AnyClass]、[String : AnyObject] 和 [String : AnyClass]。
    • 如果我在 JSONodel 对象中尝试 exactly 相同的代码,我会收到一个错误,抱怨缺少 usingEncoding 参数(它认为我正在尝试调用不同的 super.我猜是初始化过载)。如果我只是实现所有必需的初始化(包括接受 [NSObject : AnyObject]! 和 NSErrorPointer 参数的初始化),我仍然会收到错误
    • 基本上,我认为如果该确切代码在 Xcode6b6 中为您工作而不是为我工作,那么我必须在我发布的代码之外做错了什么。我会坚持下去,让你知道。
    • 在我的问题中可能会或可能不清楚的是,我所指的 JSONModel 是开源 JSON 框架 (www.jsonmodel.com)。因此,虽然您在上面提供的确切代码在操场上工作(我在其中定义了一个名为 JSONModel 的类),但使用 actual JSONModel 正在死去,并且它可能是不兼容的不知何故使用 Swift,或者我需要做一些特别的事情才能让它工作,但我还没弄清楚是什么。
    【解决方案2】:

    我在一个小型依赖注入框架中实现了类似的东西,最后我发现实现这一目标的最佳方法是存储一个实例化对象的闭包。

    这就是我将如何实现实例化器类:

    typealias Constructor = (responseObject: NSDictionary, error: NSError?) -> AnyObject
    
    class Instantiator {
        private var instantiators = [String : Constructor]()
    
        func bindKey<T : AnyObject>(key: String, withType type:T.Type, toInitializer initializer: Constructor) {
            self.instantiators[key] = initializer
        }
    
        func instanceForKey(key: String, responseObject: NSDictionary, error: NSError?) -> AnyObject? {
            if let instantiator = self.instantiators[key] {
                return instantiator(responseObject: responseObject, error: error)
            }
    
            return .None
        }
    }
    

    那么我会这样使用它:

    class MyClass {
        let x = "Test"
        init(responseObject: NSDictionary, error: NSError?) {}
    }
    
    let instantiator = Instantiator()
    
    instantiator.bindKey("GetOptions", withType: MyClass.self) { (responseObject: NSDictionary, error: NSError?) -> MyClass in
        return MyClass(responseObject: responseObject, error: error)
    }
    
    let x: MyClass! = instantiator.instanceForKey("GetOptions", responseObject: NSDictionary(), error: nil) as MyClass?
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-10-30
      • 2012-02-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-08-11
      • 1970-01-01
      • 2014-09-17
      相关资源
      最近更新 更多