0

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(). But I've got an Expected member name or constructor call after type name error for the last two lines. 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')

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.

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.

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)(). 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'.

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.

4

2 回答 2

1

要使其正常工作,您必须initcls将其类型转换为NSObject.Type. 此外,x.name仅当clsClass 类型包含该特定属性时才有效。这就是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
    }
}

打电话doStuffClassType.self

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

如果您仍然遇到任何问题,请告诉我。

于 2018-04-18T17:10:56.760 回答
1

通用的 Swift 方式怎么样。

代码将泛型类型限制为TMyClass因为它必须具有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))

或者使用协议。

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
    }
}
于 2018-04-18T17:08:15.887 回答