Как построить свойство по родовому типу в Swift? - программирование
Подтвердить что ты не робот

Как построить свойство по родовому типу в Swift?

Я создал общий класс в swift, и я хотел бы инициализировать адаптер с типом AdaptorType, но я получил компиляционную ошибку

class Sample<ItemType, AdaptorType> {
    var items = Array<ItemType>() 
    let adaptor = AdaptorType()   //Error: 'AdaptorType' is not constructible with '()'
}

Я также попробовал инициализировать его в init(), но то же самое проблемное место

class SampleGnericClass<ItemType, AdaptorType> {
    var items = Array<ItemType>() 
    let adaptor : AdaptorType

    init() {
        adaptor = AdaptorType()      //It doesn't work, same error occors here
    }
}

Какой правильный способ получить свойство адаптера, инициализированное с помощью типичного типа AdaptorType? Большое вам спасибо!

EDIT: Полный код по этому вопросу

import UIKit

protocol XYManagedObject {

}

protocol XYNetworkProtocol {

    typealias ManagedObjectType : XYManagedObject

    func object(fromItemDictionary dictionary: NSDictionary?) -> ManagedObjectType?
    func objects(fromEntryDictionary dictionary: NSDictionary?) -> Array<ManagedObjectType>?
    func actionParameters(page: UInt?) -> (action: String, parameters: Dictionary<String, String>?)
    func pageSize() -> UInt? // nil for unlimited
}

class ProductAdaptor : XYNetworkProtocol {

    var filter = Dictionary<String, String>()

    typealias ManagedObjectType = XYProductObject

    func object(fromItemDictionary dictionary: NSDictionary?) -> ManagedObjectType? {
        //... Will return an object here
        return nil
    }

    func objects(fromEntryDictionary dictionary: NSDictionary?) -> Array<ManagedObjectType>? {
        //... will return an array of objects here
        return nil
    }

    func actionParameters(page: UInt?) -> (action: String, parameters: Dictionary<String, String>?) {
        var parameters = filter
        if page {
            parameters["page"] = "\(page!)"
        }

        return ("product_list", parameters)
    }

    func pageSize() -> UInt? {
        return 100
    }
}

class XYDataManager<ItemType: XYManagedObject, AdaptorType: XYNetworkProtocol> {

    var objects = Array<ItemType>()
    let adaptor = ProductAdaptor() //work around, adaptor should be any type conform to XYNetworkProtocol

    func loadPage(page: UInt?) -> (hasNextPage: Bool, items: Array<ItemType>?) {
        let fetcher = XYFetchController()

        let ap = adaptor.actionParameters(page)
        if let fetchedResult = fetcher.JSONObjectForAPI(ap.action, parameters: ap.parameters) {

            let npage = fetchedResult["npage"].integerValue
            var hasNextPage = true
            if !npage || !page {
                hasNextPage = false
            }
            else if npage <= page {
                hasNextPage = false
            }

            let objects = adaptor.objects(fromEntryDictionary: fetchedResult)
            return (hasNextPage, (objects as Array<ItemType>?))
        }
        else {
            return (false, nil)
        }
    }
}
4b9b3361

Ответ 1

Не все объекты могут быть инициализированы без аргументов, подобных тем, которые вы пытаетесь сделать. Вы должны взять инициализированный экземпляр для инициализатора класса

Вы также можете определить свой собственный протокол, для которого требуется пустой инициализатор (добавив к нему init) и ограничив AdapterType таким протоколом

Ответ 2

Вы можете создать протокол, объявляющий инициализатор

protocol HasEmptyInitializer {
    init()
}

Затем выполните общее соответствие протоколу

class Sample<ItemType, AdaptorType:HasEmptyInitializer> {
    var items = Array<ItemType>() 
    let adaptor = AdaptorType()
}

Все, что может быть передано как AdapterType, должно также соответствовать протоколу

extension ProductAdaptor : HasEmptyInitializer {}

Ответ 3

Поскольку вы не знаете класс, вы не знаете, как создать экземпляр класса. Вы должны взять экземпляр в свой конструктор.

class SampleGenericClass<ItemType, AdaptorType> {
    var items = Array<ItemType>() 
    let adaptor : AdaptorType

    init(a: AdaptorType) {
        adaptor = a
    }
}

Интересный факт: это приводит к сбою детской площадки.