iOS中的Copy

iOS提供了copy与mutableCopy方法,copy就是复制了一个不可变的对象,而mutableCopy就是复制了一个可变的对象,下面通过几个实例来演示一下。

一、非容器类对象的copy与mutableCopy

    NSString *str = [NSString stringWithFormat:@"%@", @"create by "];
    NSLog(@"str: %p 值:%@ 引用计数:%lu", str, str, [str retainCount]);

    NSString *strCopy = [str copy];
    NSLog(@"strCopy: %p 值:%@ 引用计数:%lu", strCopy, strCopy, [strCopy retainCount]);

    NSMutableString *mStrCopy = [str mutableCopy];
    NSLog(@"mStrCopy: %p 值:%@ 引用计数:%lu", mStrCopy, mStrCopy, [mStrCopy retainCount]);

    NSMutableString *mStrCopy2 = [mStrCopy copy];
    NSLog(@"mStrCopy2:%p 值:%@ 引用计数:%lu", mStrCopy2, mStrCopy2, [mStrCopy2 retainCount]);
    //下面一句代码不注释则引起crash
//    [mStrCopy2 appendString:@"xiangpuhua"];
//    NSLog(@"mStrCopy2:%p 值:%@ 引用计数:%lu", mStrCopy2, mStrCopy2, [mStrCopy2 retainCount]);

    [mStrCopy appendString:@"xiangpuhua"];
    NSLog(@"mStrCopy:%p 值:%@ 引用计数:%lu", mStrCopy, mStrCopy, [mStrCopy retainCount]);

    NSMutableString *mStrCopy3 = [mStrCopy mutableCopy];
    NSLog(@"mStrCopy3:%p 值:%@ 引用计数:%lu", mStrCopy3, mStrCopy3, [mStrCopy3 retainCount]);
    [mStrCopy3 appendString:@"!!!"];
    NSLog(@"mStrCopy3:%p 值:%@ 引用计数:%lu", mStrCopy3, mStrCopy3, [mStrCopy3 retainCount]);

输出结果:

2017-02-27 17:49:42.859 CopyTest[12206:2131173] str: 0x60000002ade0 值:create by  引用计数:1
2017-02-27 17:49:42.859 CopyTest[12206:2131173] strCopy: 0x60000002ade0 值:create by  引用计数:2
2017-02-27 17:49:42.860 CopyTest[12206:2131173] mStrCopy: 0x600000074940 值:create by  引用计数:1
2017-02-27 17:49:42.861 CopyTest[12206:2131173] mStrCopy2:0x60000002ae20 值:create by  引用计数:1
2017-02-27 17:49:42.861 CopyTest[12206:2131173] mStrCopy:0x600000074940 值:create by xiangpuhua 引用计数:1
2017-02-27 17:49:42.861 CopyTest[12206:2131173] mStrCopy3:0x600000074a40 值:create by xiangpuhua 引用计数:1
2017-02-27 17:49:42.861 CopyTest[12206:2131173] mStrCopy3:0x600000074a40 值:create by xiangpuhua!!! 引用计数:1

由输出结果,我们可知,str与strCopy指向同一内存区域,此时str与strCopy的引用计数一样都为2。而mStrCopy则是真正意义上的复制,系统为其分配了新的内存,但指针所指向的字符串还是和str所指的一样。而对mStrCopy进行copy的时候发现mStrCopy2与mStrCopy指向不是同一个指针,说明也是进行了真正意义上的复制,由此我们可以得出以下结论:
1、对不可变对象复制,copy是指针复制(浅拷贝),而mutableCopy是对象复制(深拷贝)
2、对可变对象复制,copy与mutableCopy都是对象复制(深拷贝)。
3、对可变对象复制,copy出来的对象是不可变的。

二、容器类对象的copy与mutableCopy

容器类对象指的是NSArray、NSDictionary等。

    NSArray *arr = @[@"a"];
    NSLog(@"arr: %p 值:%@ 引用计数:%lu", arr, arr, [arr retainCount]);

    NSArray *arrCopy = [arr copy];
    NSLog(@"arrCopy: %p 值:%@ 引用计数:%lu", arrCopy, arrCopy, [arrCopy retainCount]);

    NSMutableArray *mArrCopy = [arr mutableCopy];
    NSLog(@"mArrCopy: %p 值:%@ 引用计数:%lu", mArrCopy, mArrCopy, [mArrCopy retainCount]);

    NSMutableArray *mArrCopy2 = [mArrCopy copy];
    NSLog(@"mArrCopy2:%p 值:%@ 引用计数:%lu", mArrCopy2, mArrCopy2, [mArrCopy2 retainCount]);
    //下面一句代码不注释则引起crash
//    [mArrCopy2 addObject:@"b"];
//    NSLog(@"mArrCopy2:%p 值:%@ 引用计数:%lu", mArrCopy2, mArrCopy2, [mArrCopy2 retainCount]);

    [mArrCopy addObject:@"c"];
    NSLog(@"mArrCopy:%p 值:%@ 引用计数:%lu", mArrCopy, mArrCopy, [mArrCopy retainCount]);

    NSMutableArray *mArrCopy3 = [mArrCopy mutableCopy];
    NSLog(@"mArrCopy3:%p 值:%@ 引用计数:%lu", mArrCopy3, mArrCopy3, [mArrCopy3 retainCount]);
    [mArrCopy3 addObject:@"d"];
    NSLog(@"mArrCopy3:%p 值:%@ 引用计数:%lu", mArrCopy3, mArrCopy3, [mArrCopy3 retainCount]);

输出结果:

2017-02-27 18:01:32.190 ffm[12459:2216832] arr: 0x60000001d6d0 值:(
    a
) 引用计数:1
2017-02-27 18:01:32.190 ffm[12459:2216832] arrCopy: 0x60000001d6d0 值:(
    a
) 引用计数:2
2017-02-27 18:01:32.191 ffm[12459:2216832] mArrCopy: 0x600000248940 值:(
    a
) 引用计数:1
2017-02-27 18:01:32.191 ffm[12459:2216832] mArrCopy2:0x60800001d360 值:(
    a
) 引用计数:1
2017-02-27 18:01:32.191 ffm[12459:2216832] mArrCopy:0x600000248940 值:(
    a,
    c
) 引用计数:1
2017-02-27 18:01:32.192 ffm[12459:2216832] mArrCopy3:0x608000242dc0 值:(
    a,
    c
) 引用计数:1
2017-02-27 18:01:32.192 ffm[12459:2216832] mArrCopy3:0x608000242dc0 值:(
    a,
    c,
    d
) 引用计数:1

由输出结果可知:容器类基本规则与非容器类一致,遵循一下规则
1、对不可变对象复制,copy是指针复制(浅拷贝),而mutableCopy是对象复制(深拷贝)
2、对可变对象复制,copy与mutableCopy都是对象复制(深拷贝)。
3、对可变对象复制,copy出来的对象是不可变的。
但是我们需要研究的是复制后容器内对象的变化。

    NSArray *arr = @[[NSMutableString stringWithString:@"create by "], [NSString stringWithFormat:@"%@", @"xph"]];
    NSLog(@"arr: %p 值:%@ 引用计数:%lu", arr, arr, [arr retainCount]);
    for (int i=0; i<arr.count; i++) {
        id object = arr[i];
        NSLog(@"arr中第%d个元素: %p 值:%@ 引用计数:%lu", i, object, object, [object retainCount]);
    }

    NSArray *arrCopy = [arr copy];
    NSLog(@"arrCopy: %p 值:%@ 引用计数:%lu", arrCopy, arrCopy, [arrCopy retainCount]);
    for (int i=0; i<arrCopy.count; i++) {
        id object = arrCopy[i];
        NSLog(@"arrCopy中第%d个元素: %p 值:%@ 引用计数:%lu", i, object, object, [object retainCount]);
    }

    NSMutableArray *mArrCopy = [arr mutableCopy];
    NSLog(@"mArrCopy: %p 值:%@ 引用计数:%lu", mArrCopy, mArrCopy, [mArrCopy retainCount]);
    for (int i=0; i<mArrCopy.count; i++) {
        id object = mArrCopy[i];
        NSLog(@"mArrCopy中第%d个元素: %p 值:%@ 引用计数:%lu", i, object, object, [object retainCount]);
    }

    NSMutableString *first = mArrCopy[0];
    [first appendString:@"xiangpuhua"];

    NSLog(@"arr: %p 值:%@ 引用计数:%lu", arr, arr, [arr retainCount]);
    for (int i=0; i<arr.count; i++) {
        id object = arr[i];
        NSLog(@"arr中第%d个元素: %p 值:%@ 引用计数:%lu", i, object, object, [object retainCount]);
    }

输出结果:

2017-02-27 18:13:49.963 CopyTest[12598:2286314] arr: 0x6080002281a0 值:(
    "create by ",
    xph
) 引用计数:1
2017-02-27 18:13:49.963 CopyTest[12598:2286314] arr中第0个元素: 0x608000273680 值:create by  引用计数:2
2017-02-27 18:13:49.963 CopyTest[12598:2286314] arr中第1个元素: 0xa000000006870783 值:xph 引用计数:18446744073709551615
2017-02-27 18:13:49.964 CopyTest[12598:2286314] arrCopy: 0x6080002281a0 值:(
    "create by ",
    xph
) 引用计数:2
2017-02-27 18:13:49.964 CopyTest[12598:2286314] arrCopy中第0个元素: 0x608000273680 值:create by  引用计数:2
2017-02-27 18:13:49.964 CopyTest[12598:2286314] arrCopy中第1个元素: 0xa000000006870783 值:xph 引用计数:18446744073709551615
2017-02-27 18:13:49.964 CopyTest[12598:2286314] mArrCopy: 0x60800024c4e0 值:(
    "create by ",
    xph
) 引用计数:1
2017-02-27 18:13:49.965 CopyTest[12598:2286314] mArrCopy中第0个元素: 0x608000273680 值:create by  引用计数:3
2017-02-27 18:13:49.965 CopyTest[12598:2286314] mArrCopy中第1个元素: 0xa000000006870783 值:xph 引用计数:18446744073709551615
2017-02-27 18:13:49.965 CopyTest[12598:2286314] arr: 0x6080002281a0 值:(
    "create by xiangpuhua",
    xph
) 引用计数:2
2017-02-27 18:13:49.965 CopyTest[12598:2286314] arr中第0个元素: 0x608000273680 值:create by xiangpuhua 引用计数:3
2017-02-27 18:13:49.967 CopyTest[12598:2286314] arr中第1个元素: 0xa000000006870783 值:xph 引用计数:18446744073709551615

由此可知:不管是copy还是mutableCopy,容器内元素只是实现了指针的复制(浅拷贝)。
如果要实现容器内的元素也是深拷贝,怎么办呢?

NSArray *arr = @[@[[NSMutableString stringWithString:@"create by "]].mutableCopy, [NSMutableString stringWithString:@"iOS "], [NSString stringWithFormat:@"%@", @"xph"]];
    NSArray *deepCopyArray = [[NSArray alloc] initWithArray:arr copyItems:YES];
    NSArray *deepCopyArray2 = [NSKeyedUnarchiver unarchiveObjectWithData:
                                  [NSKeyedArchiver archivedDataWithRootObject:arr]];
    NSLog(@"1: %p 值:%@ 引用计数:%lu", arr, arr, [arr retainCount]);
    NSLog(@"2: %p 值:%@ 引用计数:%lu", deepCopyArray, deepCopyArray, [deepCopyArray retainCount]);
    NSLog(@"3: %p 值:%@ 引用计数:%lu", deepCopyArray2, deepCopyArray2, [deepCopyArray2 retainCount]);
    for (int i=0; i<arr.count; i++) {
        id o1 = arr[i];
        id o2 = deepCopyArray[i];
        id o3 = deepCopyArray2[i];
        NSLog(@"1、中第%d个元素: %p 值:%@ 引用计数:%lu", i, o1, o1, [o1 retainCount]);
        NSLog(@"2、中第%d个元素: %p 值:%@ 引用计数:%lu", i, o2, o2, [o2 retainCount]);
        NSLog(@"3、中第%d个元素: %p 值:%@ 引用计数:%lu", i, o3, o3, [o3 retainCount]);
        if ([o1 isKindOfClass:[NSArray class]]) {
            for (id oo in o1) {
                NSLog(@"1、子元素: %p 值:%@ 引用计数:%lu", oo, oo, [oo retainCount]);
            }
        }
        if ([o2 isKindOfClass:[NSArray class]]) {
            for (id oo in o2) {
                NSLog(@"2、子元素: %p 值:%@ 引用计数:%lu", oo, oo, [oo retainCount]);
            }
        }
        if ([o3 isKindOfClass:[NSArray class]]) {
            for (id oo in o3) {
                NSLog(@"3、子元素: %p 值:%@ 引用计数:%lu", oo, oo, [oo retainCount]);
            }
        }
    }

输出结果:

2017-02-27 22:20:00.628 CopyTest[14436:3967892] 1: 0x60000005d010 值:(
        (
        "create by "
    ),
    "iOS ",
    xph
) 引用计数:1
2017-02-27 22:20:00.628 CopyTest[14436:3967892] 2: 0x60000005d040 值:(
        (
        "create by "
    ),
    "iOS ",
    xph
) 引用计数:1
2017-02-27 22:20:00.628 CopyTest[14436:3967892] 3: 0x60000005d490 值:(
        (
        "create by "
    ),
    "iOS ",
    xph
) 引用计数:1
2017-02-27 22:20:00.628 CopyTest[14436:3967892] 1、中第0个元素: 0x60000005cfe0 值:(
    "create by "
) 引用计数:2
2017-02-27 22:20:00.629 CopyTest[14436:3967892] 2、中第0个元素: 0x60000000afd0 值:(
    "create by "
) 引用计数:1
2017-02-27 22:20:00.629 CopyTest[14436:3967892] 3、中第0个元素: 0x60000005d2e0 值:(
    "create by "
) 引用计数:1
2017-02-27 22:20:00.629 CopyTest[14436:3967892] 1、子元素: 0x600000077700 值:create by  引用计数:4
2017-02-27 22:20:00.629 CopyTest[14436:3967892] 2、子元素: 0x600000077700 值:create by  引用计数:4
2017-02-27 22:20:00.629 CopyTest[14436:3967892] 3、子元素: 0x600000077ac0 值:create by  引用计数:1
2017-02-27 22:20:00.629 CopyTest[14436:3967892] 1、中第1个元素: 0x600000077780 值:iOS  引用计数:2
2017-02-27 22:20:00.630 CopyTest[14436:3967892] 2、中第1个元素: 0xa00000020534f694 值:iOS  引用计数:18446744073709551615
2017-02-27 22:20:00.631 CopyTest[14436:3967892] 3、中第1个元素: 0x600000077b80 值:iOS  引用计数:1
2017-02-27 22:20:00.631 CopyTest[14436:3967892] 1、中第2个元素: 0xa000000006870783 值:xph 引用计数:18446744073709551615
2017-02-27 22:20:00.631 CopyTest[14436:3967892] 2、中第2个元素: 0xa000000006870783 值:xph 引用计数:18446744073709551615
2017-02-27 22:20:00.631 CopyTest[14436:3967892] 3、中第2个元素: 0xa000000006870783 值:xph 引用计数:18446744073709551615

根据输出结果我们可知,deepCopyArray实现了一层的深拷贝,也就是说deepCopyArray实现了其内第一层元素(即数组的直接元素)的深拷贝,当数组中的元素为容器类元素时,无法实现第二层数据的深拷贝,而deepCopyArray2实现了真正的深拷贝。(官网解释

总结如下:
1、对不可变对象复制,copy是指针复制(浅拷贝),而mutableCopy是对象复制(深拷贝)
2、对可变对象复制,copy与mutableCopy都是对象复制(深拷贝)。
3、对可变对象复制,copy出来的对象是不可变的。
4、容器类对象copy与mutableCopy时,元素均为指针复制(浅拷贝)。
5、使用initWithArray:copyItems:且第二个参数为YES的时候实现了一层的深拷贝
6、容器类对象中的元素不可变时,对象复制(深拷贝)并没有真正拷贝对象,而是指针的拷贝。

三、copy关键字

(1)NSString、NSArray、NSDictionay等经常使用copy关键字。
原因:因为父类指针可以指向子类对象,使用copy的目的是为了让本对象的属性不受外界影响,使用copy无论给我传入是一个可变对象还是不可对象,我本身持有的就是一个不可变的副本,如果我们使用是strong,那么这个属性就有可能指向一个可变对象,如果这个可变对象在外部被修改了,那么会影响该属性。

//User.h文件中

@property (nonatomic, strong) NSString *name;//此时若将一个可变字符串set给name,那么此时的name则指向的是一个可变字符,那么就无法保证name的不可变性   
@property (nonatomic, copy) NSString *name;//此时若将一个可变字符串set给name,此时会执行[MutableString copy]内容复制,即深复制,将返回一个不可变字符串,即name指向的是一个不可变字符串,以后即使MutableString改变也不会影响name的值           
  例如:
NSMutableString *string = [NSMutableString stringWithString:@"origin"];//copy
NSString *stringCopy = [string copy];
[string appendString:@"origion!"]

此时的打印结果:string:originorigion!,而stringCopy仍为:origin
(2)block也经常会使用copy关键字
原因:block使用copy是从MRC遗留下来的“传统”,在MRC中,方法内部的block是在栈区的,使用copy可以把它放到堆区。在ARC中写不写都行。对于block使用copy还是strong效果是一样的,但写上copy也无伤大雅,还能时刻提醒我们:编译器自动对block进行了copy操作。

<think>好的,我现在需要解决用户提到的iOS打包时出现的'copy fail'错误。首先,我得回忆一下常见的iOS打包错误以及相关的解决方法。根据用户提供的引用内容,特别是引用[2]中提到的自动管理签名和配置文件生成,可能和代码签名或证书配置有关。 首先,用户提到的错误是在打包过程中出现的,可能与文件复制失败有关。可能的原因包括: 1. **文件路径问题**:某些文件路径中包含特殊字符或空格,导致复制过程中出错。 2. **权限问题**:项目文件或目录的权限设置不正确,导致打包工具无法访问或复制。 3. **代码签名问题**:证书或配置文件配置错误,导致在打包过程中无法正确签名应用,进而引发复制失败。 4. **资源文件冲突**:资源文件重复或命名冲突,尤其是在多目标或分包的场景下,可能引发问题。 5. **Xcode版本或配置问题**:Xcode的自动签名管理可能存在bug,或者项目配置需要调整。 接下来,我需要参考用户提供的引用内容。引用[2]提到Xcode 11之后签名证书和配置文件的管理更加自动化,因此检查自动签名设置是否正确。如果用户使用的是较旧的Xcode版本,可能需要升级或手动处理签名。 另外,引用[1]中提到uniapp在iOS下分享到微信小程序的问题,可能与资源处理有关,虽然问题不同,但可以推测iOS打包时资源处理可能存在一些共通的问题,比如资源路径或配置错误。 可能的解决步骤: 1. **检查文件路径和名称**:确保所有资源文件路径没有特殊字符或空格,尤其是中文路径或空格可能导致问题。 2. **清理构建目录**:使用Xcode的Clean Build Folder功能,删除Derived Data,然后重新构建。 3. **验证代码签名设置**:在Xcode中检查项目的Signing & Capabilities,确保启用自动管理签名,并且团队选择正确。如果有多个target或子项目,需逐一检查。 4. **检查资源文件**:确认没有重复命名的文件,尤其是在不同目录下同名的文件可能导致复制冲突。 5. **更新Xcode和依赖库**:确保使用最新版本的Xcode,并更新项目中的第三方库或框架,以修复可能的兼容性问题。 6. **查看详细日志**:在Xcode的构建日志中查找具体的错误信息,定位到导致copy fail的具体文件或步骤。 7. **权限修复**:在终端中运行`chmod`命令修复项目目录的权限,或使用`sudo`权限尝试打包。 8. **重新生成配置文件**:删除现有的provisioning profiles,让Xcode重新生成,可能解决配置文件损坏的问题。 此外,引用[3]中提到面试中关于crash处理和性能优化的问题,虽然不直接相关,但可能用户的项目中存在资源管理不当的情况,比如缓存或下载任务中的文件处理问题,间接导致打包失败。 综合以上分析,应该按照步骤逐步排查,从简单的清理和检查开始,逐步深入到代码签名和配置文件,确保每个环节都正确无误。</think>### iOS打包'copy fail'错误解决方案 #### 1. 检查文件路径与名称 - **特殊字符/空格**:确保项目中所有文件路径不含空格或特殊符号(如`#`、`!`)。若存在中文路径,建议改为英文[^1]。 - **重复文件**:检查是否存在同名文件被多次添加到不同目录,可能导致复制冲突。 #### 2. 清理构建缓存 - **操作步骤**: 1. 在Xcode中点击菜单栏的`Product` → `Clean Build Folder`。 2. 手动删除`DerivedData`目录(路径:`~/Library/Developer/Xcode/DerivedData`)。 3. 重启Xcode后重新打包。 #### 3. 验证代码签名配置 - **自动签名设置**: 1. 在Xcode项目导航器中选中主Target。 2. 进入`Signing & Capabilities`标签页。 3. 勾选`Automatically manage signing`,并确认`Team`选择正确[^2]。 4. **多Target项目**:需对每个子Target重复上述步骤。 - **手动修复配置文件**: - 删除现有配置文件:前往`~/Library/MobileDevice/Provisioning Profiles`,移除所有文件。 - 重新打包让Xcode自动生成新配置文件。 #### 4. 检查资源文件冲突 - **资源重复**:在`Build Phases` → `Copy Bundle Resources`中,检查是否存在重复添加的资源文件。 - **大文件处理**:若资源文件过大(如超过100MB),可能触发系统限制,建议压缩或分片。 #### 5. 查看详细错误日志 - **操作步骤**: 1. 在Xcode中打开`Report Navigator`(左侧导航栏最后一个图标)。 2. 选择最近的打包日志,展开`Copy`相关步骤。 3. 查找红色错误标记,定位具体失败文件。 #### 6. 修复文件权限 - **终端操作**: ```bash cd 项目根目录 chmod -R 755 . ``` - **Xcode权限**:如果项目存储在系统保护目录(如`Desktop`、`Documents`),建议迁移到其他路径。 #### 7. 更新开发环境 - **升级Xcode**:前往App Store安装最新版本。 - **更新CocoaPods**: ```bash sudo gem install cocoapods pod update ``` #### 8. 特殊场景处理 - **UniApp项目**:若使用跨平台框架,检查`manifest.json`中iOS配置是否包含无效字符,必要时重新生成原生工程。 - **第三方SDK冲突**:通过注释法逐步排除第三方库,确认是否由特定SDK引起。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值