xcode 如何在 Swift 中通过泛型类型构造属性?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/24190837/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-15 05:04:37  来源:igfitidea点击:

How to construct a property by generic type in Swift?

iosxcodecocoa-touchgenericsswift

提问by Sensheng Xu

I created a generic class in swift and I'd like to initialise an adaptor with the type 'AdaptorType', but I received an compiling error

我在 swift 中创建了一个通用类,我想初始化一个类型为“AdaptorType”的适配器,但我收到一个编译错误

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

I also tried initialise it in init(), but same problem toke place

我也尝试在 init() 中初始化它,但同样的问题发生

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

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

What's the right way to get adaptor property initialised with the generic type AdaptorType? Thank you a lot!

使用泛型类型 AdaptorType 初始化适配器属性的正确方法是什么?非常感谢!

EDIT: Full codes about this question

编辑:关于这个问题的完整代码

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

回答by drewag

Not all objects can be initialized without arguments like you are trying to do. You have to take an initialized instance to the initializer of you class

并非所有对象都可以像您尝试做的那样在没有参数的情况下进行初始化。你必须将一个初始化的实例带到你的类的初始化器中

You may also be able to define your own protocol that requires an empty initializer (by adding initto it) and restrict AdapterType to be of that protocol

您也可以定义自己的协议,该协议需要一个空的初始值设定项(通过添加init)并将 AdapterType 限制为该协议

回答by drawnonward

You can make a protocol that declares the initializer

您可以制定一个声明初始化程序的协议

protocol HasEmptyInitializer {
    init()
}

Then have the generic conform to the protocol

然后让通用符合协议

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

Anything that might be passed as AdapterType must also conform to the protocol

任何可能作为 AdapterType 传递的东西也必须符合协议

extension ProductAdaptor : HasEmptyInitializer {}

回答by teradyl

You may be able to force cast if you know exactly what type your generic is in the case.

如果您确切地知道您的泛型在这种情况下是什么类型,您也许能够强制转换。

Instantiate an object of a generic type in Swift

在 Swift 中实例化一个泛型类型的对象

回答by Kevin

Since you don't know the class, you don't know how to create an instance of the class. You have to take an instance in your constructor.

由于您不了解该类,因此您不知道如何创建该类的实例。您必须在构造函数中使用一个实例。

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

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

Fun fact: this makes the playground crash.

有趣的事实:这会使操场崩溃。