iphone - 如何对具有嵌套数组/字典的 NSArray 和 NSDictionary 进行真正的深度复制?

标签 iphone nsdictionary nsmutabledictionary deep-copy

问题:有没有一种方法可以使用现有的 Objective-C 方法来对 NSDictionary 或 NSArray 进行完整的深层复制,而它们本身也有嵌套的字典或数组?

那是我读到的问题可能是当它遇到嵌套字典或数组时,它只复制指向嵌套项目的指针,而不是真正复制该项目。

背景:作为我的一个例子,我尝试使用 NSUserDefaults 加载/保存以下配置,并且在加载时需要将从 NSUserDefault 获取的不可变副本转换为可变副本,然后再进行更改。

  • 项目(NSDictionary)
    • 项目(NSDictionary)
      • aString: NSString
      • aString2:NSString
      • 日期:NSDate
      • aDate2:NSDate
      • aBool: BOOL
      • aTI1:NSTimeInterval
      • aTI2:NSTimeInterval
      • 关键字 (NSArray)
        • 关键字:NSString
        • 关键字:NSString

最佳答案

几年前,我出于完全相同的原因编写了一些类别方法,将整个用户默认树转换为可变的。它们就在这里——使用它们需要您自担风险! :-)

//
//  SPDeepCopy.h
//
//  Created by Sherm Pendley on 3/15/09.
//

#import <Cocoa/Cocoa.h>

// Deep -copy and -mutableCopy methods for NSArray and NSDictionary

@interface NSArray (SPDeepCopy)

- (NSArray*) deepCopy;
- (NSMutableArray*) mutableDeepCopy;

@end

@interface NSDictionary (SPDeepCopy)

- (NSDictionary*) deepCopy;
- (NSMutableDictionary*) mutableDeepCopy;

@end
<小时/>
//
//  SPDeepCopy.m
//
//  Created by Sherm Pendley on 3/15/09.
//

#import "SPDeepCopy.h"


@implementation NSArray (SPDeepCopy)

- (NSArray*) deepCopy {
    unsigned int count = [self count];
    id cArray[count];

    for (unsigned int i = 0; i < count; ++i) {
        id obj = [self objectAtIndex:i];
        if ([obj respondsToSelector:@selector(deepCopy)])
            cArray[i] = [obj deepCopy];
        else
            cArray[i] = [obj copy];
    }

    NSArray *ret = [[NSArray arrayWithObjects:cArray count:count] retain];

    // The newly-created array retained these, so now we need to balance the above copies
    for (unsigned int i = 0; i < count; ++i)
        [cArray[i] release];

    return ret;
}
- (NSMutableArray*) mutableDeepCopy {
    unsigned int count = [self count];
    id cArray[count];

    for (unsigned int i = 0; i < count; ++i) {
        id obj = [self objectAtIndex:i];

        // Try to do a deep mutable copy, if this object supports it
        if ([obj respondsToSelector:@selector(mutableDeepCopy)])
            cArray[i] = [obj mutableDeepCopy];

        // Then try a shallow mutable copy, if the object supports that
        else if ([obj respondsToSelector:@selector(mutableCopyWithZone:)])
            cArray[i] = [obj mutableCopy];

        // Next try to do a deep copy
        else if ([obj respondsToSelector:@selector(deepCopy)])
            cArray[i] = [obj deepCopy];

        // If all else fails, fall back to an ordinary copy
        else
            cArray[i] = [obj copy];
    }

    NSMutableArray *ret = [[NSMutableArray arrayWithObjects:cArray count:count] retain];

    // The newly-created array retained these, so now we need to balance the above copies
    for (unsigned int i = 0; i < count; ++i)
        [cArray[i] release];

    return ret;
}

@end

@implementation NSDictionary (SPDeepCopy)

- (NSDictionary*) deepCopy {
    unsigned int count = [self count];
    id cObjects[count];
    id cKeys[count];

    NSEnumerator *e = [self keyEnumerator];
    unsigned int i = 0;
    id thisKey;
    while ((thisKey = [e nextObject]) != nil) {
        id obj = [self objectForKey:thisKey];

        if ([obj respondsToSelector:@selector(deepCopy)])
            cObjects[i] = [obj deepCopy];
        else
            cObjects[i] = [obj copy];

        if ([thisKey respondsToSelector:@selector(deepCopy)])
            cKeys[i] = [thisKey deepCopy];
        else
            cKeys[i] = [thisKey copy];

        ++i;
    }

    NSDictionary *ret = [[NSDictionary dictionaryWithObjects:cObjects forKeys:cKeys count:count] retain];

    // The newly-created dictionary retained these, so now we need to balance the above copies
    for (unsigned int i = 0; i < count; ++i) {
        [cObjects[i] release];
        [cKeys[i] release];
    }

    return ret;
}
- (NSMutableDictionary*) mutableDeepCopy {
    unsigned int count = [self count];
    id cObjects[count];
    id cKeys[count];

    NSEnumerator *e = [self keyEnumerator];
    unsigned int i = 0;
    id thisKey;
    while ((thisKey = [e nextObject]) != nil) {
        id obj = [self objectForKey:thisKey];

        // Try to do a deep mutable copy, if this object supports it
        if ([obj respondsToSelector:@selector(mutableDeepCopy)])
            cObjects[i] = [obj mutableDeepCopy];

        // Then try a shallow mutable copy, if the object supports that
        else if ([obj respondsToSelector:@selector(mutableCopyWithZone:)])
            cObjects[i] = [obj mutableCopy];

        // Next try to do a deep copy
        else if ([obj respondsToSelector:@selector(deepCopy)])
            cObjects[i] = [obj deepCopy];

        // If all else fails, fall back to an ordinary copy
        else
            cObjects[i] = [obj copy];

        // I don't think mutable keys make much sense, so just do an ordinary copy
        if ([thisKey respondsToSelector:@selector(deepCopy)])
            cKeys[i] = [thisKey deepCopy];
        else
            cKeys[i] = [thisKey copy];

        ++i;
    }

    NSMutableDictionary *ret = [[NSMutableDictionary dictionaryWithObjects:cObjects forKeys:cKeys count:count] retain];

    // The newly-created dictionary retained these, so now we need to balance the above copies
    for (unsigned int i = 0; i < count; ++i) {
        [cObjects[i] release];
        [cKeys[i] release];
    }

    return ret;
}

@end

关于iphone - 如何对具有嵌套数组/字典的 NSArray 和 NSDictionary 进行真正的深度复制?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5453481/

相关文章:

ios - 如何检查 NSMutableDictionary 中的 UIImageView 是否与同一 NSMutableDictionary 中的另一个 UIImageView 相交?

ios - 在 ios 9.1 中使用什么来代替 UIScreen.mainScreen().applicationFrame?

iphone - 当应用程序从后台删除或在 iOS 中删除时发生的事件

objective-c - 我可以使用 NSDictionaryController 作为字典的字典吗?

ios - 将字典对象从 Obj-C 传递到 Swift

ios - 如何在 NSUserDefaults 中存储和检索 NSMutableDictionary?

objective-c - 是否有 NSMutableDictionary 文字语法来删除元素?

php - NSURL请求:EXC_BAD_ACCESS

ios - 将一些哈希码从 .net 语法转换为 objective-c

ios - 签名捕获 IOS