Создайте подкласс UIImage с добавленными свойствами

Я пытаюсь создать подкласс UIImage с добавленным свойством, но когда я создаю удобство инициализации, я не могу вызвать назначенный UIImage init init (named name: String), потому что по какой-то причине он не унаследован.

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

Любые идеи?


person Hikarus    schedule 15.01.2016    source источник


Ответы (3)


В объявлении named: initializer есть строка «не унаследованная»:

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

Я не уверен, что именно означает «не унаследовано», но похоже, что его реальная природа - «удобный инициализатор», и вы не можете использовать его в подклассах. По крайней мере так себя ведет. Итак, я предлагаю вам пойти по следующему пути:

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
    }
}

С другой стороны, обычно вам не нужно создавать подклассы UIImage. В большинстве случаев создание класса-оболочки было бы достаточным и гораздо более подходящим.

person Shaman    schedule 15.01.2016
comment
красивый! хитрость заключается в том, чтобы инициализировать его с помощью CGImage и обойти ненаследуемое ограничение :) - person Hikarus; 22.01.2016

UIImage не предназначен для создания подклассов (вы заметите отсутствие «примечаний к подклассам» в его документации). Как вы уже выяснили, есть много маленьких каверзных проблем с попыткой создать подкласс. Это довольно распространено в классах Cocoa, которые тесно связаны с классами Core Foundation (в данном случае UIImage и CGImageRef).

Как правило, вы должны решить эту проблему с помощью композиции, а не наследования. Создайте новую структуру, включающую свойства image и imageType, и просто используйте ее.

Если есть какая-то более глубокая причина, по которой вам нужно присоединить тип к реальному UIImage, это можно сделать с помощью трюков во время выполнения (см. objc_setAssociatedObject), но это следует зарезервировать для случаев, когда композиция невозможна. Чаще всего это когда вы передаете объект какому-то API, который позже вернет его вам, и вам нужно передать вместе с ним некоторую информацию по сторонним каналам. Я часто использовал это при работе с UIAlertView, но обычно простая композиция лучше.

person Rob Napier    schedule 15.01.2016

Создание подкласса 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")
    }

}
person Shaheen Ghiassy    schedule 12.12.2017