Obj-C工厂方法没有暴露给Swift子类

时间:2014-10-24 15:24:15

标签: objective-c inheritance swift nsimage

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

根据Apple的文档,Objective-C工厂方法“在Swift中被映射为便利初始化器。”

因此NSImage工厂方法

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

被映射到Swift的

NSImage(named: "anything")

另外,在Swift Programming Language一书中,我们看到子类初始化器继承的规则是:

“规则1 如果您的子类没有定义任何指定的初始值设定项,它会自动继承其所有超类指定的初始值设定项。

规则2 如果您的子类提供了所有超类指定初始化程序的实现 - 通过按照规则1继承它们,或者通过提供自定义实现作为其定义的一部分 - 那么它会自动继承所有超类便利初始化程序。“

因此遵循子类

class T : NSImage { }

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

我错过了什么?

1 个答案:

答案 0 :(得分:3)

原因似乎是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 UIImage https://gist.github.com/bartekchlebek/d61154add8525218ae3a

进行了烹饪

你可以在那里看到,我创建了一个名为MyImage的{​​{1}}的子类,并覆盖了所有UIImage的初始值设定项,并将NSLog置于其中并返回零。

- (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不需要这样做。