使用添加的属性创建 UIImage 的子类

Create a subclass of UIImage with added properties

我正在尝试创建一个添加了 属性 的 UIImage 的子类,但是当我创建一个方便的初始化时,我无法调用 UIImage 的指定初始化 init(named name: String) 因为对于由于某些原因它没有被继承。

class myUIImage: UIImage {
    var imageType$: String?
    convenience init(imageName$ imageName$: String) {
        self.init(...?)
        self.imageType$ = // ...
    }
}

有什么想法吗?

named:initializer 声明中有 "not inherited" 个字符串:

public /*not inherited*/ init?(named name: String) // load from main bundle

我不确定 "not inherited" 到底代表什么,但看起来它的真实性质是 "convenience initializer" 并且你不能在 subclasses 中使用它。至少它的行为是这样的。 所以,我建议你走下面的路:

class TheImage: UIImage {
    var param: String! = nil
    convenience init?(param: String) {
        guard let image = UIImage(named: "TheImage") where nil != image.cgImage else {
            return nil
        }
        self.init(cgImage: image.cgImage!)
        self.param = param
    }
}

从另一方面来说,通常你真的不需要子class UIImage。在大多数情况下,创建包装器 class 就足够了,而且更合适。

UIImage 不是为子类设计的(您会注意到其文档中缺少 "Subclassing notes")。正如您所发现的那样,尝试对其进行子类化有很多棘手的小问题。这在与 Core Foundation 类 密切相关的 Cocoa 类 中很常见(在本例中为 UIImageCGImageRef)。

通常你应该用组合而不是继承来解决这个问题。创建一个包含 imageimageType 属性的新结构,然后使用它。

如果有更深层次的原因需要将类型附加到真实的 UIImage,这可以通过运行时技巧来完成(请参阅 objc_setAssociatedObject),但这应该保留用于某些情况不可能合成的地方。最常见的是当您将一个对象传递给一些 API 稍后将它返回给您时,您需要将一些 side-channel 信息与其一起传递。我在处理 UIAlertView 时经常使用它,但通常简单的组合更好。

子类化 UIImage 有点古怪。但是可以做到

class PlaceHolderIcon: UIImage {

    // any additional properties can go here

    override init() {
        let image = UIImage(named: "image-name")!
        super.init(cgImage: image.cgImage!, scale: UIScreen.main.scale, orientation: .up)
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    required convenience init(imageLiteralResourceName name: String) {
        fatalError("init(imageLiteralResourceName:) has not been implemented")
    }

}