精华内容
下载资源
问答
  • 1)、让自己的类可以使用copy修饰符的步骤: a)、让自己的类遵循NSCopying协议 b)、实现NSCopying协议中必须实现的代理方法: - (id)copyWithZone:(NSZone *)zone; 示例代码: - (id)copyWithZone:(NSZone *)zone ...

    答:

    1)、让自己的类可以使用copy修饰符的步骤:

    a)、让自己的类遵循NSCopying协议
    b)、实现NSCopying协议中必须实现的代理方法:
        - (id)copyWithZone:(NSZone *)zone;
    

    示例代码:

    - (id)copyWithZone:(NSZone *)zone {
        //创建实例的方式比较特殊
        Person *p = [[[self class] allocWithZone:zone] init];   
        
        p.name = self.name;
        p.age = self.age;
        
        return p;
    }
    

    2)、如何重写带copy关键字的setter:

    - (void)setName:(NSString *)name {
        //[_name release];
        _name = [name copy];
    }
    

    tips:

    Copy & MutableCopy

    使用copy或mutableCopy方法可以创建一个对象的副本

    • copy
      需要实现NSCoppying协议
      这些创建的是不可变副本(如NSString、NSArray、NSDictionary)
    • mutableCopy
      需要先实现NSMutableCopying协议
      创建的是可变副本(如NSMutableString、NSMutableArray、NSMutableDictionary)
    • copy的目的是建立副本,同时修改原始对象和复本不会互相干扰

    查看上篇博客,了解更多关于深复制 & 浅复制的内容

    • 深复制:
      内容拷贝,源对象和副本指向的是不同的两个对象
      源对象引用计数器不变,副本计数器设置为1

    • 浅复制:
      指针拷贝,源对象和副本指向的是同一个对象
      对象的引用计数器+1,其实相当于做了一次retain操作

    结论:只有不可变对象创建不可变副本(copy)才是浅复制,其他都是深复制

    展开全文
  • 在iOS开发中经常见到copy,strong修饰符。在NSString的属性中会看到copy和strong的存在。大部分情况下NSString的属性都是copy。那么strong和copy的区别是什么? @property (nonatomic, copy) NSString *string1; ...

    在iOS开发中经常见到copy,strong修饰符。在NSString的属性中会看到copy和strong的存在。大部分情况下NSString的属性都是copy。那么strong和copy的区别是什么?

    @property (nonatomic, copy)     NSString *string1;
    @property (nonatomic, strong)   NSString *string2;

    定义方法

    - (void)judge
     {
         NSString *string3 = @"abc";
         self.string1 = string3;
         self.string2 = string3;
    
        NSLog(@"string3===%p %p", string3, &string3);
        NSLog(@"string1===%p %p", self.string2, &_string1);
        NSLog(@"string2===%p %p", self.string2, &_string2);
    
     }

    打印结果

    string3===0x10d7210b0 0x7fff525af298
    string1===0x10d7210b0 0x7fe11bc0ebb0
    string2===0x10d7210b0 0x7fe11bc0ebb8

    此时将string3 = @”qwr”;
    打印结果

    string3===0x10cc1d130 0x7fff530b4298
    string1===0x10cc1d0b0 0x7fbc06e0a170
    string2===0x10cc1d0b0 0x7fbc06e0a178

    我们发现只有string3有变。strin1和string2指向的还是原来的值

    结论:使用NSString类的时候,无论使用copy还是strong,当再次改变时,还是指向原来的位置。也就是浅拷贝

    使用NSMutableString声明

        NSMutableString *string3 = [NSMutableString stringWithFormat:@"abc"];
    
        self.string1 = string3;
        self.string2 = string3;
        NSLog(@"%@", self.string1);
        NSLog(@"%@", self.string2);
        NSLog(@"%@", string3);
    
        [string3 appendString:@"qwr"];
        NSLog(@"%@", self.string1);
        NSLog(@"%@", self.string2);
        NSLog(@"%@", string3);
    

    打印结果

    string1 ==== abc
    string2 ==== abcqwr
    string3 ==== abcqwr
    

    当string3改变的时候,用strong修饰的string2随着一起变动。而用copy修饰的string1没有变动

    结论:使用NSMutableString类的时候,使用copy修饰会产生新的对象,两者指向新的位置,也就是深拷贝

    展开全文
  • 注意:一提到让自己的类用 copy 修饰符,我们总是想覆写copy方法,其实真正需要实现的却是 “copyWithZone” 方法。 以第一题的代码为例:  // .h文件  // http://weibo.com/luohanchenyilong/  // ...

    出题者简介: 孙源(sunnyxx),目前就职于百度

    整理者简介:陈奕龙,目前就职于滴滴出行。

    若想令自己所写的对象具有拷贝功能,则需实现 NSCopying 协议。如果自定义的对象分为可变版本与不可变版本,那么就要同时实现 NSCopying 与 NSMutableCopying 协议。

     

     

    具体步骤:

    1. 需声明该类遵从 NSCopying 协议
    2. 实现 NSCopying 协议。该协议只有一个方法:
      - (id)copyWithZone:(NSZone *)zone;
      注意:一提到让自己的类用 copy 修饰符,我们总是想覆写copy方法,其实真正需要实现的却是 “copyWithZone” 方法。

    以第一题的代码为例:

        // .h文件

        // http://weibo.com/luohanchenyilong/

        // https://github.com/ChenYilong

        // 修改完的代码


        typedef NS_ENUM(NSInteger, CYLSex) {

            CYLSexMan,

            CYLSexWoman

        };


        @interface CYLUser : NSObject<NSCopying>


        @property (nonatomic, readonly, copy) NSString *name;

        @property (nonatomic, readonly, assign) NSUInteger age;

        @property (nonatomic, readonly, assign) CYLSex sex;


        - (instancetype)initWithName:(NSString *)name age:(NSUInteger)age sex:(CYLSex)sex;

        + (instancetype)userWithName:(NSString *)name age:(NSUInteger)age sex:(CYLSex)sex;


        @end

    然后实现协议中规定的方法:

    - (id)copyWithZone:(NSZone *)zone {

        CYLUser *copy = [[[self class] allocWithZone:zone] 

                         initWithName:_name

                                      age:_age

                                      sex:_sex];

        return copy;

    }

    但在实际的项目中,不可能这么简单,遇到更复杂一点,比如类对象中的数据结构可能并未在初始化方法中设置好,需要另行设置。举个例子,假如 CYLUser 中含有一个数组,与其他 CYLUser 对象建立或解除朋友关系的那些方法都需要操作这个数组。那么在这种情况下,你得把这个包含朋友对象的数组也一并拷贝过来。下面列出了实现此功能所需的全部代码:

    // .h文件

    // http://weibo.com/luohanchenyilong/

    // https://github.com/ChenYilong

    // 以第一题《风格纠错题》里的代码为例


    typedef NS_ENUM(NSInteger, CYLSex) {

        CYLSexMan,

        CYLSexWoman

    };


    @interface CYLUser : NSObject<NSCopying>


    @property (nonatomic, readonly, copy) NSString *name;

    @property (nonatomic, readonly, assign) NSUInteger age;

    @property (nonatomic, readonly, assign) CYLSex sex;


    - (instancetype)initWithName:(NSString *)name age:(NSUInteger)age sex:(CYLSex)sex;

    + (instancetype)userWithName:(NSString *)name age:(NSUInteger)age sex:(CYLSex)sex;

    - (void)addFriend:(CYLUser *)user;

    - (void)removeFriend:(CYLUser *)user;


    @end

    // .m文件

    // .m文件

    // http://weibo.com/luohanchenyilong/

    // https://github.com/ChenYilong

    //


    @implementation CYLUser {

        NSMutableSet *_friends;

    }


    - (void)setName:(NSString *)name {

        _name = [name copy];

    }


    - (instancetype)initWithName:(NSString *)name

                             age:(NSUInteger)age

                             sex:(CYLSex)sex {

        if(self = [super init]) {

            _name = [name copy];

            _age = age;

            _sex = sex;

            _friends = [[NSMutableSet alloc] init];

        }

        return self;

    }


    - (void)addFriend:(CYLUser *)user {

        [_friends addObject:user];

    }


    - (void)removeFriend:(CYLUser *)user {

        [_friends removeObject:user];

    }


    - (id)copyWithZone:(NSZone *)zone {

        CYLUser *copy = [[[self class] allocWithZone:zone]

                         initWithName:_name

                         age:_age

                         sex:_sex];

        copy->_friends = [_friends mutableCopy];

        return copy;

    }


    - (id)deepCopy {

        CYLUser *copy = [[[self class] allocWithZone:zone]

                         initWithName:_name

                         age:_age

                         sex:_sex];

        copy->_friends = [[NSMutableSet alloc] initWithSet:_friends

                                                 copyItems:YES];

        return copy;

    }


    @end

    以上做法能满足基本的需求,但是也有缺陷:

    如果你所写的对象需要深拷贝,那么可考虑新增一个专门执行深拷贝的方法。

    【注:深浅拷贝的概念,在下文中有介绍,详见下文的:用@property声明的 NSString(或NSArray,NSDictionary)经常使用 copy 关键字,为什么?如果改用 strong 关键字,可能造成什么问题?

    在例子中,存放朋友对象的 set 是用 “copyWithZone:” 方法来拷贝的,这种浅拷贝方式不会逐个复制 set 中的元素。若需要深拷贝的话,则可像下面这样,编写一个专供深拷贝所用的方法:

    - (id)deepCopy {

        CYLUser *copy = [[[self class] allocWithZone:zone]

                         initWithName:_name

                         age:_age

                         sex:_sex];

        copy->_friends = [[NSMutableSet alloc] initWithSet:_friends

                                                 copyItems:YES];

        return copy;

    }

    至于如何重写带 copy 关键字的 setter这个问题,

    如果抛开本例来回答的话,如下:

    - (void)setName:(NSString *)name {

        //[_name release];

        _name = [name copy];

    }

    不过也有争议,有人说“苹果如果像下面这样干,是不是效率会高一些?”

    - (void)setName:(NSString *)name {

        if (_name != name) {

            //[_name release];//MRC

            _name = [name copy];

        }

    }


    展开全文
  • 我发觉面试的时候很喜欢问属性(@property)的修饰符,什么 assign、retain、copy、weak、strong 的区别之类。尤其喜欢问 copy 属性。本文就和大家一起来详细扒一扒copy 修饰符相关内容,一起来看看吧,希望对...

    我发觉面试的时候很喜欢问属性(@property)的修饰符,什么 assignretaincopyweakstrong 的区别之类。尤其喜欢问 copy 属性。本文就和大家一起来详细扒一扒copy 修饰符相关内容,一起来看看吧,希望对大家学习Objective-C有所帮助。

      什么时候需要 copy 修饰符?

      典型是这种

      NSMutableString* string = [[NSMutableString alloc] initWithString"Hello, World"];

      Test* test = [[Test alloc] init];

      test.title = string;

      [string appendString"Hello World"];

      外面创建一个可变的对象,之后给 Test.title 赋值。这里 title 属性,需要使用 copy, 不应该用 retain。不然之后外部对象改变了,就会引起 title 的改变。

      同理,NSMutableArray, NSMutableDictionary 也是如此,比如 UINavigationController.viewControllers 属性就是使用copy。不过复制容器代价会更大些。我们更经常看到的是 NSString 的 copy

      copy 和 mutableCopy

      Cocoa 很多容器类都有两种类型,一种是可变(可以修改)的,比如 NSMutableString,一种是不可变(不可修改)的,比如 NSString

      指所以区分可变不可变,是因为不可变对象会更简单。比如写代码时,因为知道对象不可变,就可以一开始就分配好固定的内存,刚刚好,不多不少;假如是可变对象,就可能需要预留一点空间。再比如,在多线程时,访问不可变的对象可以不上锁,因为它状态根本不可变,自然也就没有同步的需要;而可变对象就需要上锁。

      copy 也有两种,从语意上定义,使用 copy 会复制出不可变的对象,而使用 mutableCopy 会复制出对应的可变类型对象。但实际上,copy 和 mutableCopy 是由各个类独立实现的,最终 copy 得到的是否真是不可变对象,实际上是不确定的。比如

      NSMutableString* string0 = [[NSMutableString alloc] initWithString"Hello, World"];NSLog(@"%@", NSStringFromClass([[string0 copyclass]));

      NSMutableString* string1 = [[NSMutableString alloc] init];NSLog(@"%@", NSStringFromClass([[string1 copyclass]));

      会打印出 __NSCFString 和 __NSCFConstantString。这说明 string0 的 copy 产生 NSMutableString 对象,而 string1 copy产生了 NSString 对象。

      我们写代码的时候应该依赖于语意(或者接口定义),而不能依赖于具体实现,实现会更容易变化。copy 应该根据语意,将对象都当成不可修改的,这样肯定没有错。

      copy 语意和实现

      copy 语意上是复制一份数据,前一份数据修改之后,不会影响后一份。但语意和实现是分离的,具体实现上,是不是真的复制一份,是不固定的,是由各个类独立实现的。

      NSString* str = @"Hello, World";NSString* str1 = [str copy];NSLog(@"%p, %p", str, str1);

      比如对于 NSString 等不可变对象的时候,调用 copy 会直接返回自身。你会看到 [str copy] 得到的对象,其实就是 str

      这样做,并没有违背 copy 语意。对于不可变对象,本来就不能修改,自然也就不会影响复制后的数据,也就没有必要复制了。。更应该从语意上(从接口)中看,不要过于依赖于实现。在这点上,有很多人没有区分好语意和实现。面试的时候,就发觉面试官特别喜欢纠结于 copy 是否真的复制了。

      更具体一些,

      copy 最终会调用 NSCopying 协议的函数:

      - (id)copyWithZonenullable NSZone *)zone;

      mutableCopy 会调用 NSMutableCopying 协议的函数:

      - (id)mutableCopyWithZonenullable NSZone *)zone;

      每个不同的类,都可以根据自己的具体情况,实现自身的 copy 和 mutableCopy 语意。

      随便提一下,NSZone 这个类是用来封装具体的内存分配和释放,有点像内存池。以前的内存比较紧张,根据不同的情况使用不同的内存分配方式,也很有必要。但现在 NSZone 属于历史遗留问题了,基本都为 nil, 基本不用管它。你就算想自己重新写一个 NSZone, 也很难写得比系统内置的好。

      翻了一下 objc runtime 的源码,设置属性最终会调用 reallySetProperty 函数,里面有这样的代码:

      if (copy) {

      newValue = [newValue copyWithZone:nil];

      else if (mutableCopy) {

      newValue = [newValue mutableCopyWithZone:nil];

      else {

      if (*slot == newValue) return;

      newValue = objc_retain(newValue);

      }

      最后习题

      这其实是我面试过程中的题目。

      #import

      @interface Test : NSObject {

      }@property (nonatomiccopy) NSMutableArray* array;@end

      @implementation Test

      @end

      int main(int argc, const char* argv[]) {

      @autoreleasepool {

      NSMutableArray* array = [[NSMutableArray alloc] init];

      Test* test = [[Test alloc] init];

      test.array = array;  // (1)

      NSLog(@"%@", NSStringFromClass([test.array class]));

      }

      return 0;

      }

      在语句(1test.array = array; 之后,test.array 究竟实际上是什么类型。

      我面试过程当中,推断应该是调用 copy, 这样实际上应该是 NSArray 类型。但我当时不确定,我不清楚编译器是否可能智能到看到 NSMutableArray 类型,就将其转化成 mutableCopy

      回家后,我试了试,打印出类型。确实是 NSArray 类型。

      这种题目已经稍微有点刁难了。我写了这样久 Objective-C 代码,还从来没有看到过属性中类型为可变的,属性的类型为可变,本来就有点问题。

    来源:网络

    展开全文
  • 当我们在做开发时, 一定会用到@property这个修饰符. @property 的本质正如以下这条公式: @property = ivar + getter + setter; “属性” (property)有两大概念:ivar(实例变量)、存取方法(access method = ...
  • @property (nonatomic, copy) NSMutableArray *array; NSMutableArray *array = [NSMutableArray arrayWithObjects:@"1", @"2", nil]; self.array = array; [self.array addObject:@"3"]; NSLog(@"array = %@", ...
  • 2.后面用strong修饰符和weak修饰符分别打印的是malloc的和stack的,但是无论哪种,只要copy就是变成malloc类型了 3.最后一种就是上面介绍的,stackBlock经过传参,自动变成了mallocBlock 来看一张表,看看三种类型...
  • 又是一个老生常谈的话题,可是貌似这个问题,好多ios开发工程师并不能理解透彻,所以简单记录分析一下深复制与浅复制的原理以及strong,copy修饰符的原理和使用。 一、深复制与浅复制 1、区分深复制与浅...
  • iOS开发-------属性用copy、strong修饰的区别 Copy,Strong的区别需要了解点内存管理的知识,Strong是ARC下引入的修饰,相当于手动管理内存(MRC)下的retain,在相关代码下,常常看到有的人用copy修饰NSString,...
  • NSArray的修饰符使用strong时,如果用可变数组给其赋值,会出现可变数组改变时,array也会改变的情况 这显然是不希望出现的 但是使用copy将不会出现此问题 NSMutableArray *mutableArray = [NSMutableArray ...
  • strong与copy修饰符 strong修饰的属性,对该属性赋值时发生指针拷贝,即浅拷贝; copy修饰的属性,对该属性赋值时发生内容拷贝,即深拷贝。(存在特殊Case) 通过重写对象的setter方法实现。 当将不可变对象...
  • copy 在iOS开发中,对象之间传值都是使用引用计数器增加的方式,这种方式的适用于当对象的某属性的值改变时,引用该对象的不同指针会同时改变,因为这两个指针指向的是同一个内存地址,当一个指针执行的对象属性值...
  • OC 属性修饰符

    2017-08-01 18:45:29
    getter / setter readwrite / readonly atomic / nonatomic assign / strong / weak / retain / copy 其它临时变量 getter、setter@property (nonatomic, assign, getter=isLoading ,setter=loading:) BOOL
  • 这其实是用到了最初的MRC的知识,在setter方法的时候会调用copy strong retain 等,到这里我不得不衍生一下copy和mutableCopy 的区别在我的另一篇文章里https://mp.csdn.net/postedit @property (nonatomic,copy) ...
  • NSString用copy还是strong修饰

    千次阅读 2019-08-30 15:25:51
    如果使用copy修饰属性,在进行赋值的时候,会先做一个类型判断,如果赋的值是一个不可变的字符串,则走strong的策略,进行的是浅拷贝;如果是可变的字符串,则进行深拷贝创建一个新的对象。所以如果我们确定是给...
  • ios初步修饰符简介

    2015-07-22 18:13:23
    @property 修饰符 什么情况使用 weak 关键字,相比 assign 有什么不同? 怎么用 copy 关键字?...如何让自己的类用 copy 修饰符?如何重写带 copy 关键字的 setter? @property 的本质是什么?ivar、getter
  • vue .sync修饰符的用法

    千次阅读 2018-09-28 11:24:02
    那么同时,vue中也提供了一种解决方案.sync修饰符。在此之前,希望你已经知道了vue中是如何通过事件的方式实现子组件修改父组件的data的。如果你对此还不了解父子组件如何通过$emit实现双向通信,那就点我先了解下吧...
  • volatile修饰符的作用前言线程可见性简绍JAVA线程模型案例指令重排简绍案例 前言 volatile在多线程开发中是可以经常看到的变量修饰符,本文主要是比较浅显的介绍volatile的作用。 线程可见性 简绍 JAVA线程模型 案例...
  • iOS block修饰符copy还是strong

    千次阅读 2020-10-20 10:59:29
    Block修饰符选择: block本身是像对象一样可以retain,和release。但是,block在创建的时候,它的内存是分配在栈(stack)上,而不是在堆(heap)上。他本身的作于域是属于创建时候的作用域,一旦在创建时候的作用域外面...
  • property属性修饰符经常的用法 当我们定义一个字符串属性时,通常我们会这样写: @property (nonatomic, copy) NSString *name; 当我们定义一个NSMutableArray类型的属性时,通常我们会这样写: @property ...
  • vue中的.sync修饰符

    千次阅读 多人点赞 2018-05-10 21:05:03
    vue中的.sync修饰符 在Vue中,子父组件最常用的通信方式就是通过props进行数据传递,props值只能在父组件中更新并传递给子组件,在子组件内部,是不能改变传递进来的props值,这样保证了数据单行流通。但有时候,...
  • 常类型是指使用类型修饰符const说明的类型,常类型的变量或对象的值是不能被更新的。(当然,我们可以偷梁换柱进行更新:) 修改常量:加mutable mutable class A { public: A(int i=0):test(i) { } void ...
  • 1.不可变数组的copy 浅复制,复制的是指向对象的指针。 2.不可变数组的mutableCopy 为深复制,复制的是指针所指的对象。但是对象中各个指针变量中保存的还是以前元素的指针。 3.可变数组的copy 为深复制...
  • C++ const 修饰符

    千次阅读 多人点赞 2021-05-04 12:17:03
    C++ const 修饰符是什么, const 修饰符的用途以及规范.

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 40,007
精华内容 16,002
关键字:

copy修饰符