【问题标题】:Calling an instance method in designated initializer of a Swift class在 Swift 类的指定初始化程序中调用实例方法
【发布时间】:2015-12-27 12:57:25
【问题描述】:

在 Swift 编程语言中,这是强制性的

“指定的初始化程序必须确保其类引入的所有属性在委托给超类初始化程序之前都已初始化。” source of quote from another s/o

否则会显示类似下面的错误

属性 'self.baz' 未在 super.init 调用中初始化

我想在 Swift 中实现以下 Objective-C 代码:

@interface FooBar : NSObject

@property (nonatomic, readonly) NSString *baz;

@end

@implementataion FooBar

@synthesize baz = _baz;

- (instancetype)initWithString:(NSString *)string {
    self = [super init];
    if (self) {
        _baz = [self parseString:string];
    }
    return self;
}

- (NSString *)parseString:(NSString *)string {
    // Perform something on the original string
    return ...;
}

@end

以下实现会引发如上所述的编译器错误:

class FooBar: NSObject {
    let baz: NSString?

    init(string: NSString?) {
        super.init()
        baz = parseString(string)
    }

    private func parseString(string: NSString?) -> NSString? {
        // Perform something on the original string
        return ...;
    }
}

如果我执行以下操作,我会收到一条错误消息

在 super.init 初始化 self 之前,在方法调用 'parseString' 中使用 self

class FooBar: NSObject {
    let baz: NSString?

    init(string: NSString?) {
        baz = parseString(string)
        super.init()
    }

    private func parseString(string: NSString?) -> NSString? {
        // Perform something on the original string
        return string;
    }
}

所以我目前的解决方案是使用私有类方法:

class FooBar: NSObject {
    let baz: NSString?

    init(string: NSString?) {
        baz = FooBar.parseString(string)
        super.init()
    }

    private class func parseString(string: NSString?) -> NSString? {
        // Perform something on the original string
        return ...;
    }
}

我的问题是是否有更好的方法来实现相同的目标,还是私有类方法是最好的方法?

【问题讨论】:

    标签: objective-c swift designated-initializer code-migration


    【解决方案1】:

    正如您正确提到的,编译器抱怨 “在 super.init 初始化 self 之前在方法调用 'parseString' 中使用 self”。原因是编译器必须确保您在完成初始化之前不会访问self 上的任何内容。因为编译器不想(甚至不能)在初始化完成之前检查每个传出的方法调用,所以它只是不允许在初始化完成之前使用任何 self。

    幸运的是,您的方法 parseString 不想更改或访问任何属性。因此,您可以并且应该将其设为非实例函数。如果它与FooBar 的实例无关,为什么它只能在FooBar 的实例上可用?

    您可以像以前那样简单地将其设为staticclass 函数,这非常好。

    但我会更进一步,将其完全移出FooBar。有几个选项:

    • 创建一个 Helper 类,您也可以在其中将其定义为 class function
    • 创建一个Helper 类,您将其定义为instance function,并在您的类FooBar 中创建一个Helper 实例,或者创建一个全局实例并在init 中传递该实例。

    【讨论】:

    • 为了更符合原始代码的精神,您可以在声明中将 baz 初始化为 nil。毕竟,这就是 Objective-C 方面正在发生的事情。这样可以避免您收到的初始错误。
    • @Avi 但这会取消它是一个常量。
    • parseString 更改为私有类方法如何将baz 保留为常量?事实是,无论如何它都是在声明之后分配的。这不是一个常数。此外,在最初的 Objective-C 中,它也不是一个常数。
    • @Avi:你可以在Swift中声明常量后初始化它们。
    • @Avi,请看他的问题中发布的代码OP,baz仍然是一个常数。唯一允许你给它赋值的时候是在构造函数中。
    猜你喜欢
    • 1970-01-01
    • 2014-07-29
    • 2023-03-12
    • 1970-01-01
    • 2014-10-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多