zoukankan      html  css  js  c++  java
  • AJ整理问题之:copy,对象自定义copy 什么是property

    AJ分享,必须精品

    copy

    copy的正目的

    copy 目的:建立一个副本,彼此修改,各不干扰
    Copy(不可变)和MutableCopy(可变)针对Foundation框架的数据类型。
    对于自定义类,copy就是可变的。


    可变数组的copy

    这里用NSMutableArray为例子。

    // 可变=》可变&不可变,内存地址都会变化
    void copyDemo1()
    {
        NSMutableArray *arrayM = [NSMutableArray arrayWithObjects:@(1), @(2), nil];
        NSLog(@"%@ %p %@", arrayM, arrayM, arrayM.class);
    
        // 1. 可变 => 可变
        NSMutableArray *aM = [arrayM mutableCopy];
        NSLog(@"%@ %p %@", aM, aM, aM.class);
    
        // 2. 可变 => 不可变
        NSArray *a = [arrayM copy];
        NSLog(@"%@ %p %@", a, a, a.class);
    }
    

    这里写图片描述

    由结果我们得到一下结论
    1:arrayM,aM,a是三个不同的对象
    2:可变 => 可变 (arrayM是可变的,用mutableCopy给aM 得出aM.class是NSArrayM )
    3:可变 => 不可变(aM是可变的,用copy给a 得出a.class是NSArrayI)


    不可变数组的copy

    void copyDemo2()
    {
        NSArray *array = @[@(1), @(2)];
        NSLog(@"%@ %p %@", array, array, array.class);
    
        // 1. 不可变 => 可变
        NSMutableArray *aM = [array mutableCopy];
        NSLog(@"%@ %p %@", aM, aM, aM.class);
    
        // 2. 不可变 => 不可变(浅复制)
        // 指针的复制,引用计数+1
        NSArray *a = [array copy];
        NSLog(@"%@ %p %@", a, a, a.class);
    }

    这里写图片描述

    由上结果我们得到结论
    1:不可变 => 可变 内存地址变了,class由NSArrayI=>NSArrayM
    2:不可变 => 不可变 内存地址一致,class由NSArrayI=>NSArrayI
    作用是指针的复制,引用计数+1。术语(浅复制)

    3:浅复制:不可变=>不可变
       深复制:其他三种情况!
       (在这里记忆时候记住都不能改就是浅复制,能改就是深复制,相对于记忆四中情况更容易记忆。)
    

    哪里用的最多呢?

    这里用的最多

    @property (nonatomic, copy) NSString *name;

    NSString
    Block

    都使用copy属性,copy属性,在赋值时,会默认做一次copy操作,让他变成“不可变的类型”
    strong相当于MRC中的retain,在赋值时,只是引用计数+1
    

    在@property中使用什么杨的类型说明他,他就有什么样的方法。
    例如这段代码:

     NSMutableString *strM = [NSMutableString stringWithString:@"zhangsan"];
        NSLog(@"%@ %p %@", strM, strM, strM.class);
    
        Person *p = [[Person alloc] init];
        p.name = strM;
    
        NSLog(@"%@ %p %@", p.name, p.name, p.name.class);
    
        // 修改"源",p.name会跟着修改
        [strM setString:@"lisi"];
        NSLog(@"==== %@ %p", strM, strM);
        NSLog(@"%@ %p", p.name, p.name);

    如果用strong来说明person的name,当我们修改strM的时候,p.name也会跟着改,如果用的时copy的话,那么他就不会被修改。这里取决于Person类中的@property
    简单理解,如果用了copy就是复制一个String给name
    而如果用了strong,就仅仅是引用计数+1。
    p.name能不能修改呢?这里我们不能直接修改,我们需要用一个万能指针。

    // 修改p.name
        id obj = p.name;
        [obj setString:@"wangwu"];
        NSLog(@"==== %@ %p", strM, strM);
        NSLog(@"%@ %p", p.name, p.name);

    这要用strong能改,这样类会变得不安全。我们把strong改成copy
    当我们修改“源”的时候

    [strM setString:@"lisi"];

    p.name还是原样的。
    而这时候修改属性的方法编译没有问题,但是运行时候会报错
    这里写图片描述
    Attempt to mutate immutable object with xxx
    视图修改一个不可变的类型,使用方法xxx

    对于”可变类型”的属性,不要使用copy描述符定义,否则赋值后,就是不可变了!


    copy自定义对象

    [object copy]

    想要让对象能用copy方法 [p copy]
    (自定义对象要实现copy功能)
    1> 遵守NSCopying协议(本质上就是方便程序员编写代码时候,有快捷提示)
    2> 实现- (id)copyWithZone:(NSZone *)zone
    (zone,区域,很少用)
    所有的copy方法,最终都会调用copyWithZone方法
    copy操作一个对象,复制给一个新的对象。

    - (id)copyWithZone:(NSZone *)zone
    {
        // 1> 实例化对象,self 是对象
        // self.class能够保证继承的子类同样使用copy方法
        Person *p = [[self.class alloc] init];
    
        // 2> 给属性赋值
        p.name = self.name;
        p.age = self.age;
    
        // 3> 返回新对象
        return p;
    }
    

    这时候我们这样调用

    void copyDemo5()
    {
        Person *p = [[Person alloc] init];
        p.name = @"zhangsan";
        p.age = 18;
    
        NSLog(@"%@", p);
    
        Person *p1 = [p copy];
        p1.name = @"lisi";
        NSLog(@"%@", p1);
    }
    

    这里写图片描述
    这时候我们就能调用自己定义的类对象的copy方法了,并且可以产生一个对象。
    注意:这里的p1.name = @”lisi”并不是修改,而是重新赋值。不要让copy给弄迷糊了。


    2015年05月20日补充

    类对象等的理解

    类:是一种结构,它表示对象的类型,对象引用类来获取和本身有关的各种信息,特别是运行什么代码来处理每种操作。

    对象:是一种结构,它包含值和指向其类的隐藏指针。

    实例:对象的另一种称呼。

    消息:是对象可以执行的操作,用于通知对象去做什么。对象接收消息后,将查询对应的类,以便查找正确的代码来运行。

    方法:是为响应消息而运行的代码,根据对象的类,消息可以调用不同的方法。

    接口:是对象的类应该提供特殊的特性的描述。


    什么是property?

    property是一种代码生成机制,能够生成不同类型的getter/setter函数,特别是如果你想要用点(.)操作符号来存取变量的话,你就能必须使用property。

    如何使用property?

    用法如:@property (attribute1,attribute2) float value;

    这些attribute包括:

    readonly 表示这个属性是只读的,就是只生成getter方法,不会生成setter方法。

    readwrite 可读可写(默认)设置可访问级别。

    assign:简单赋值,不更改索引计数

    copy:建立一个索引数为1的对象,然后释放旧对象

    retain:释放(release)旧对象,将旧对象的值赋予输入对象,再提高输入对象的索引计数为1

    nonatomicnonatomic 非原子性访问,不加同步,多线程并发访问会提高性能。注意,如果不加此属性,
    则默认是两个访问方法都为原子型事务访问。

    前两个只是简单的设定变量的可读写性。

    详细解释:copy其实是建立了一个相同的对象,而retain不是:

    比如一个NSString对象,地址为0x1111,内容为@”cat” ,copy到另外一个NSString之后,地址为0x2222,内容相同,新的对象retain为1,旧有对象没有变化。

    retain 到另一个NSString之后,地址相同(建立一个指针,指针拷贝),内容当然相同,这个对象的retain值+1,也就是说,retain是指针拷贝,copy是内容拷贝。在拷贝之前,都会释放旧的对象。

    assign:简单赋值,不更改索引计数(Reference Counting)。

    copy:建立一个索引计数为1的对象,然后释放旧对象

    retain:释放旧的对象,将旧对象的值赋予输入对象,再提高输入对象的输入对象的索引计数为1

    使用assign:对基础数据类型(NSInteger)和C数据类型(int ,float,double,char等)

    使用copy:对NSString

    使用retain:对其他NSObject和其子类。

  • 相关阅读:
    01.网页学习阶段、整站分析、规划
    书签搬运
    如何判断两个链表相交及找到第一个相交点
    Windows平台使用git bash管理github中的工程
    二级指针的操作
    结构体的内存对齐
    大端和小端
    剑指Offer——面试题26:复杂链表的复制
    使用editcap命令将ERF格式转换为pcap格式
    如何在STL的map中使用结构体作为键值
  • 原文地址:https://www.cnblogs.com/luolianxi/p/4990363.html
Copyright © 2011-2022 走看看