简体   繁体   English

传递用于方法内部的类类型

[英]Pass a class type for use inside a method

In order to reduce cut-and-paste code in this app, I'm trying to pass class names around in order to tell a method which way it should process some data. 为了减少此应用程序中的剪切和粘贴代码,我正在尝试传递类名,以告诉方法应该以何种方式处理某些数据。 I have something like the following: 我有类似以下内容:

class MyClass : NSObject {
    var name : String = ""
}

class OneClass : MyClass {
    override init() {
        super.init()
        self.name = "One"
    }
}

class TwoClass : MyClass {
    override init() {
        super.init()
        self.name = "Two"
    }
}


class Thing : NSObject {
    func doStuff(withClass cls: AnyClass) -> String {
        let x = cls.init()
        return x.name
    }
}

let z = Thing()
print(z.doStuff(withClass: OneClass))
print(z.doStuff(withClass: TwoClass))

Passing withClass cls: AnyClass the parser pushed me to change let x = cls() to let x = cls.init() . 传递withClass cls: AnyClass解析器促使我将let x = cls()更改为let x = cls.init() But I've got an Expected member name or constructor call after type name error for the last two lines. 但是在最后两行的Expected member name or constructor call after type name错误Expected member name or constructor call after type name我有一个Expected member name or constructor call after type name The recommended fixes both cause other problems. 推荐的修复程序都会引起其他问题。

The first suggestion, adding the () constructor after the class name, causes new errors on those lines: Cannot convert value of type 'OneClass' to expected argument type 'AnyClass' (aka 'AnyObject.Type') 第一个建议是,在类名之后添加()构造函数,从而在这些行上引起新的错误: Cannot convert value of type 'OneClass' to expected argument type 'AnyClass' (aka 'AnyObject.Type')

Taking the second suggestion and changing them to OneClass.self and TwoClass.self gets rid of the parser errors, but when I execute the code it just runs forever.. never erroring out, and never completing. OneClass.self第二个建议并将其更改为OneClass.selfTwoClass.self摆脱了解析器错误,但是当我执行代码时,它将永远运行..永远不会出错,也永远不会完成。

I found a recommendation elsewhere that suggests I should change the Thing.doStuff() parameters to expect MyClass instead of AnyClass , but that causes another set of new problems. 我在其他地方找到了一条建议,建议我应更改Thing.doStuff()参数以期望MyClass而不是AnyClass ,但这会导致另一组新问题。

First, the parser starts complaining about the cls.init() call, and the series of fixes it suggests eventually lead to something that makes no sense: let x = cls.type(of:;; init)() . 首先,解析器开始抱怨cls.init()调用,并且它提出的一系列修复最终导致了没有意义的事情: let x = cls.type(of:;; init)() The parser ends up in a suggestion loop where it keeps adding more semi-colons in the middle of the statement. 解析器最终进入建议循环,在该循环中,它在语句中间不断添加更多分号。

Second, I'm back to type mismatch errors on the calls to doStuff() in the last two lines: Cannot convert value of type 'OneClass.Type' to expected argument type 'MyClass' . 其次,在最后两行中, Cannot convert value of type 'OneClass.Type' to expected argument type 'MyClass'在对doStuff()的调用中返回类型不匹配错误: Cannot convert value of type 'OneClass.Type' to expected argument type 'MyClass'

There's obviously something I'm not getting here about passing types as arguments, but none of the googling I've done has landed me on something that explains the problems I'm seeing. 显然,关于将类型作为参数传递,我并没有得到解决,但是我所做的任何一次谷歌搜索都没有使我着迷于可以解释我所遇到的问题的东西。

How about the generic Swift way. 通用的Swift方法怎么样。

The code constrains the generic type T to MyClass since it must have a name property. 该代码将泛型T约束为MyClass因为它必须具有name属性。

class MyClass : NSObject {
    var name : String

    override required init() {
        self.name = ""
        super.init()
    }
}

class OneClass : MyClass {
    required init() {
        super.init()
        self.name = "One"
    }
}

class TwoClass : MyClass {
    required init() {
        super.init()
        self.name = "Two"
    }
}


class Thing : NSObject {
    func doStuff<T : MyClass>(withClass cls: T.Type) -> String {
        let x = cls.init()
        return x.name
    }
}

let z = Thing()
print(z.doStuff(withClass: OneClass.self))
print(z.doStuff(withClass: TwoClass.self))

Or use a protocol. 或使用协议。

protocol Nameable {
    var name : String { get }
    init()
}

class MyClass : NSObject, Nameable { ...

...

class Thing : NSObject {
    func doStuff<T : Nameable>(withClass cls: T.Type) -> String {
        let x = cls.init()
        return x.name
    }
}

To get this working, you must call init on cls after typecasting it to NSObject.Type . 为了使它工作,必须在将其类型转换为NSObject.Type之后在cls上调用init Also, x.name only works if cls Class type contains that particular property. 另外, x.name仅在cls类类型包含该特定属性时才有效。 This is the reason x is then typecasted to MyClass . 这就是x然后被强制转换为MyClass的原因。

class Thing : NSObject
{
    func doStuff(withClass cls: AnyClass) -> String?
    {
        let x = (cls as? NSObject.Type)?.init()
        if let x = x as? MyClass
        {
            return x.name
        }
        return nil
    }
}

Call doStuff with ClassType.self ClassType.self调用doStuff

print(z.doStuff(withClass: OneClass.self))
print(z.doStuff(withClass: TwoClass.self))

Let me know if you still face any issues. 让我知道您是否仍然遇到任何问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM