Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/ios/117.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ios 如何在swift中通过泛型实现对象合并?_Ios_Swift_Oop_Generics - Fatal编程技术网

Ios 如何在swift中通过泛型实现对象合并?

Ios 如何在swift中通过泛型实现对象合并?,ios,swift,oop,generics,Ios,Swift,Oop,Generics,假设我有一个班级编号: class Number { var val: Double? } 并有该类的两个实例,A和B。 现在想象一下,我想通过如下语句将B合并到A merge(B, into: A) 现在我当然可以这样写函数了: func merge(from: Number, into: Number){ into.val = from.val } 但这根本不是可重用的。有没有一种方法可以编写一个通用的合并类 更新:尽管一些答案提供了良好可行的解决方案,但没有一个是“通

假设我有一个班级编号:

class Number {
    var val: Double?
}
并有该类的两个实例,
A
B
。 现在想象一下,我想通过如下语句将
B
合并到
A

merge(B, into: A)
现在我当然可以这样写函数了:

func merge(from: Number, into: Number){
    into.val = from.val
}
但这根本不是可重用的。有没有一种方法可以编写一个通用的合并类

更新:尽管一些答案提供了良好可行的解决方案,但没有一个是“通用”的(这里的通用是指非技术性的方式)。因此,看看这些答案,我得到了一些启示,下面是我正在考虑的解决方案:将Number设置为NSObject子类,并声明所有可以合并为动态的属性。例如:

class Number: NSObject {
    //Put the required init and initWithCoder: here
    dynamic var val: Double?
}
然后声明可合并类必须遵守的协议

protocol Mergeable: class {
    var mergeablePropertyKeys:[String] {get}
}
然后声明执行合并的全局函数:

func merge<U: Mergeable, Mergeable where U.Type == V.Type>(from: U, into:V){
    for property in U.mergeablePropertyKeys {
        V.setValue(U.valueForKey(property), property)
    }
}
func合并(从:U,到:V){
对于U.mergeablePropertyKeys中的属性{
V.setValue(U.valueForKey(属性),属性)
}
}
我知道这是行不通的,因为要合并的参数不一定是
NSObjects

  • 如何确保
    merge
    的参数都是
    NSObjects?
  • 通过简单地获取对象的动态值列表,可以避免指定所有可合并值的名称吗

我不确定您期望的是什么,但有一个通用的解决方案:

class Number<T> {
    var val: T?
}

protocol Merge {
    func merge(from: Self, into: Self)
}

extension Number: Merge {
    func merge(from: Number, into: Number) {
        into.val = from.val
    }
}
类号{
var val:T?
}
协议合并{
func合并(从:Self,到:Self)
}
分机号码:合并{
func合并(从:编号,到:编号){
into.val=from.val
}
}
协议 让我们定义一个
HasValue
协议(仅适用于类),如下所示

protocol HasValue: class {
    typealias T
    var val: T? { get set }
}
合并 现在我们可以定义一个泛型函数

func merge<U: HasValue, V:HasValue where U.T == V.T>(from: U, into:V) {
    into.val = from.val
}
场景2:参数具有不同的类型,但其值具有相同的类型 我没有将
Merge
的两个参数约束为具有相同的类型,我只是检查这两个参数的
val
属性必须具有相同的类型

因此,我们还可以合并具有相同类型val的不同类的不同实例,如

class Phone: HasValue {
    var val: Int?
}

class Computer: HasValue {
    var val: Int?
}

let iPhone = Phone()
iPhone.val = 10

let iMac = Computer()
iMac.val = 9

merge(iPhone, into: iMac)
print(iMac.val) // Optional(10)
场景3:参数具有泛型类型
类框:HasValue{
瓦尔:什么?
}
设boxOfString=Box()
boxOfString.val=“你好,世界”
设boxOfInt=Box()
boxOfInt.val=12

merge(boxOfString,into:boxOfInt)//听起来您想要的是一个使用反射来合并属性的通用函数。反射在Swift中是有限的,但是使用。我以前使用过这个方法来构建一个泛型-您可以做类似的事情,但不必解析json字典来映射两个对象的属性

使用反射在swift中执行此操作的示例:

func merge<T>(itemToMerge:T) {
    let mirrorSelf = Mirror(reflecting: self)
    let mirrorItemToMerge = Mirror(reflecting: itemToMerge)
    for mirrorSelfItem in mirrorSelf.children {
        // Loop through items in mirrorItemToMerge.
        for mirrorImageItem in mirrorItemToMerge.children {
            // If you have a parameter who's name is a match, map the value
            // OR You could add any custom mapping logic you need for your specific use case
            if mirrorSelfItem.label == mirrorImageItem.label {
                // To set values, use self.setValue(valueToSet, forKey: propertyName)
                self.setValue(mirrorImageItem.value as? AnyObject, forKey: mirrorImageItem.label!)
            }
        }
    }
}
func合并(itemtomege:T){
让镜子自己=镜子(反射:自我)
让mirrorItemToMerge=镜像(反射:itemToMerge)
对于mirrorSelf.children中的mirrorSelf项{
//在mirrorItemToMerge中循环项目。
对于mirrorItemToMerge.children中的mirrorImageItem{
//如果您有一个名称匹配的参数,请映射该值
//或者,您可以为您的特定用例添加所需的任何自定义映射逻辑
如果mirrorSelfItem.label==mirrorImageItem.label{
//要设置值,请使用self.setValue(valueToSet,forKey:propertyName)
self.setValue(mirrorImageItem.value为?AnyObject,forKey:mirrorImageItem.label!)
}
}
}
}
这假设定义合并方法的对象是NSObject的子类(因此它可以利用NSKeyValueCoding)。您还可以将其设置为静态方法,可以合并任意NSObject类型的任意2个对象:

static func merge<T1: NSObject, T2: NSObject>(itemChanging:T1, itemToMerge:T2) {
    let mirrorSelf = Mirror(reflecting: itemChanging)
    let mirrorItemToMerge = Mirror(reflecting: itemToMerge)
    for mirrorSelfItem in mirrorSelf.children {
        // Loop through items in mirrorItemToMerge.
        for mirrorImageItem in mirrorItemToMerge.children {
            // If you have a parameter who's name is a match, map the value
            // OR You could add any custom mapping logic you need for your specific use case
            if mirrorSelfItem.label == mirrorImageItem.label {
                // To set values, use self.setValue(valueToSet, forKey: propertyName)
                self.setValue(mirrorImageItem.value as? AnyObject, forKey: mirrorImageItem.label!)
            }
        }
    }
}
静态函数合并(itemChanging:T1,itemToMerge:T2){
让mirrorSelf=镜像(反射:项目更改)
让mirrorItemToMerge=镜像(反射:itemToMerge)
对于mirrorSelf.children中的mirrorSelf项{
//在mirrorItemToMerge中循环项目。
对于mirrorItemToMerge.children中的mirrorImageItem{
//如果您有一个名称匹配的参数,请映射该值
//或者,您可以为您的特定用例添加所需的任何自定义映射逻辑
如果mirrorSelfItem.label==mirrorImageItem.label{
//要设置值,请使用self.setValue(valueToSet,forKey:propertyName)
self.setValue(mirrorImageItem.value为?AnyObject,forKey:mirrorImageItem.label!)
}
}
}
}

泛型合并类是什么意思?全局通用合并函数?定义通用合并函数的协议?或者,可以通过协议实现,我想,我不太确定如何实现。你是说映射吗?在Swift中使用
NSObject
,确实意味着走错了方向。@appzYourLife我也有这种感觉,但我们看得更清楚吗?如果我们有好的ol'c指针,这将非常容易。我有一个合并协议的想法,但为了避免像那样的样板代码,我希望可以在其中定义合并的属性。而不是into.val=from.val,只提及val将是最理想的。但是当我想合并的不仅仅是
val
时会发生什么?如果有一个对象有1000个属性需要合并怎么办?如果有一个对象有1000个属性需要合并怎么办?你应该先分解那个物体。“它太大了,没用了。”维金戈塞贡多,你明白我的意思了。我不想为我想要合并的每个属性都有一个协议。遗憾的是,它只做了一半的工作。获取一个对象的所有属性+值是一种很好的方法,但是设置它们怎么样?在SwiftSerializable git repo中签出反序列化方法。它也能处理这个问题。在您的情况下,虽然您不会创建新对象,但它只会使用已经存在的对象。setValue是您所需要的-键值编码
func merge<T>(itemToMerge:T) {
    let mirrorSelf = Mirror(reflecting: self)
    let mirrorItemToMerge = Mirror(reflecting: itemToMerge)
    for mirrorSelfItem in mirrorSelf.children {
        // Loop through items in mirrorItemToMerge.
        for mirrorImageItem in mirrorItemToMerge.children {
            // If you have a parameter who's name is a match, map the value
            // OR You could add any custom mapping logic you need for your specific use case
            if mirrorSelfItem.label == mirrorImageItem.label {
                // To set values, use self.setValue(valueToSet, forKey: propertyName)
                self.setValue(mirrorImageItem.value as? AnyObject, forKey: mirrorImageItem.label!)
            }
        }
    }
}
static func merge<T1: NSObject, T2: NSObject>(itemChanging:T1, itemToMerge:T2) {
    let mirrorSelf = Mirror(reflecting: itemChanging)
    let mirrorItemToMerge = Mirror(reflecting: itemToMerge)
    for mirrorSelfItem in mirrorSelf.children {
        // Loop through items in mirrorItemToMerge.
        for mirrorImageItem in mirrorItemToMerge.children {
            // If you have a parameter who's name is a match, map the value
            // OR You could add any custom mapping logic you need for your specific use case
            if mirrorSelfItem.label == mirrorImageItem.label {
                // To set values, use self.setValue(valueToSet, forKey: propertyName)
                self.setValue(mirrorImageItem.value as? AnyObject, forKey: mirrorImageItem.label!)
            }
        }
    }
}