Obj-C工厂方法未公开给Swift子类



更具体地说,即使继承了所有其他方便的init,imageNamed也不会暴露给NSImage的Swift子类。

根据苹果的文档Objective-C工厂方法"在Swift中被映射为方便的初始化程序。"

因此,NSImage工厂方法

+ (NSImage *)imageNamed:(NSString *)name

被映射到Swift的

NSImage(named: "anything")

此外,在Swift编程语言的书中,我们看到子类初始值设定项继承的规则是:

"规则1如果您的子类没有定义任何指定的初始化器,它会自动继承所有超类指定的初始化程序。

规则2如果您的子类提供了其所有超类指定初始化器的实现——要么按照规则1继承它们,要么在其定义中提供自定义实现——那么它会自动继承所有超类便利初始化器。"

因此,子类

class T : NSImage { }

将继承所有超类的初始值设定项,包括指定的和方便的,但以下内容将不起作用 let I = T(named: "anything")

我错过了什么?

原因似乎是named:初始值设定项的返回类型为NSImage
class NSImage : NSObject, NSCopying, NSCoding, NSSecureCoding, NSPasteboardReading, NSObjectProtocol, NSPasteboardWriting {
    /*All instance variables are private*/
    init?(named name: String) -> NSImage /* If this finds & creates the image, only name is saved when archived */

而其他(并非所有)初始化程序没有返回类型

    init(size aSize: NSSize)
    init?(data: NSData) /* When archived, saves contents */
    init?(contentsOfFile fileName: String) /* When archived, saves contents */
    init?(contentsOfURL url: NSURL) /* When archived, saves contents */
    init?(byReferencingFile fileName: String) /* When archived, saves fileName */
    init(byReferencingURL url: NSURL) /* When archived, saves url, supports progressive loading */

因此,如果您有一个T类,它是NSImage的子类,您会期望T(named:)返回T的实例,但如果您不提供自己的实现,则会调用超类实现,正如我们在声明中看到的,它返回NSImage

为什么它与所有其他初始化程序不同?我不知道
也许NSImage使用的底层实现和缓存机制导致了这种不一致性。但更重要的是,+[NSImage imageNamed:]不调用任何指定的NSImage初始化器。

看看我用Cocoa Touch的UIImage制作的这个例子:https://gist.github.com/bartekchlebek/d61154add8525218ae3a

您可以在那里看到,我创建了一个名为MyImageUIImage子类,并覆盖了所有UIImage的初始值设定项,将NSLog放入其中并返回nil。

在中

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions

我调用-[MyImage imageNamed:]并注意到,放置在指定初始化器中的NSLog都没有打印出来。我还打印了用-[MyImage imageNamed:]创建的实例的类,您可以看到它不是MyImage,而是UIImage(抛开我在所有初始化程序中返回nil的事实不谈;)


总之,+[UIImage imageNamed:]不调用UIImage的任何指定初始化程序,因此重写它们不会使+[MyImage imageNamed:]返回MyImage的实例。我希望NSImage也能有同样的表现。

这种微妙之处导致Swift不继承named:初始值设定项,因为swift需要便利初始化程序通过指定的初始值设定器,而Objective-C不需要。

最新更新