copy和mutableCopy
1、一个对象使用copy或mutableCopy方法可以创建对象的副本2、copy - 需要先实现NSCopying协议,创建的是不可变得副本(如NSString、NSArray、NSDictionary)3、mutableCopy - 需要先实现NSMutableCopying协议,,创建的是可变副本(如NSMutableString、NSMutableArray、NSMutableDictionary)4、深复制:内容拷贝,源对象和副本指向不同的两个对象。源对象引用计时器不变,副本计数器设置为15、浅复制:指针拷贝,源对象和副本指向的是同一个对象。对象的引用计数器+1,其实相当于做了一次retain操作6、只有不可变对象创建不可变副本(copy)才是浅复制,其他都是深复制copy语法的目的:改变副本的时候,不会影响到源对象为自定义类添加复制功能1、如果想自定义copy,那么就必须遵守NSCopying,并且实现copyWithZone方法2、如果想自定义mutableCopy,那么就必须遵守NSMutableCopying,并且实现mutableCopyWithZone:方法3、以copy为例,建议用[self class]代替直接类名 - (id)copyWithZone:(NSZone *)zone { id copy = [[[self class ] allocWithZone:zone] init]; // 做一些属性的初始化 return copy; } // 演示字符串的拷贝 NSString *string = [[NSString alloc] initWithFormat:@ "age is %i" , 21]; // 1 // 产生了一个新的对象,引用计数器为1.源对象的引用计数器不变 NSMutableString *str = [string mutableCopy]; // 1 NSLog(@ "str: &zi" , [str retainCount]); // 1 NSLog(@ "string: %zi" , [string retainCount]); // 1 // str和string不是相同对象 NSLog(@ "%i" , str == string); // 修改str看string是否有被修改 [str appendString@ "123456" ]; NSLog(@ "str = %@" , str); NSLog(@ "string = %@" , string); [str release]; // 0 [string release]; // 0 // 如果一个对象是不可变的,copy的对象也是不可变的,系统会直接返回被copy的对象本身 // copy产生的是不可变副本,由于源对象本身就不可变,所以为了性能着想,copy会直接返回源对象本身,相当于源对象的retain操作,引用计数器+1 NSString *s1 = [[NSString alloc] initWithFormat:@ "age is %i" , 21]; NSLog(@ "s1: %zi" , [s1 retainCount]); // 1 NSString *s2 = [s1 copy]; NSLog(@ "s1: %zi" , [s1 retainCount]); // 2 NSLog(@ "%i" , s2 == s1); |
@interface Student : NSObject <NSCopying> // copy代表setter方法会release旧对象,copy新对象 // 修改外面的变量,并不会影响到内部的成员变量 // 建议:NSString一般用copy策略,其他对象一般用retain @property (nonatomic, cop)NSString *name; + (id)studentWithName:(NSString *)name; @end |
@implementation Student + (id)studentWithName:(NSString *)name { Student *stu = [[[Student alloc] init] autorelease]; stu.name = name; return stu; } // 这里创建的副本对象不要求释放 - (id)copyWithZone:(NSZone *)zone { Student *copy = [[Student allocWithZone:zone] init]; copy.name = self.name; return copy; } - ( void )description { return [NSString stringWithFormat:@ "[name = %@]" , _name]; } - ( void )dealloc { [_name release]; [super release]; } @end |
// 这里写self class是为了防止子类在创建的过程中导致类型错误 Student *stu = [[[[self class ] alloc] init] autorelease]; NSMutableString *string = [NSMutableString stringWithFormat@ "age is %i" , 21]; stu.name = string; [string addendString:@ "abcd" ]; // 如果Student.h中的*name是retain,那么修改了string,stu.name也被修改了 // 如果Student.h中的*name是copy,那么修改了string,stu.name就不会被修改 NSLog(@ "name = %@" , stu.name); NSLog(@ "string = %@" , string); // Student的copy Student *stu1 = [Student studentWithName:@ "student1" ]; // 如果Student没有实现NSCopying协议,那么会报错:unrecognized selector sent to instance.... Student *stu2 = [stu1 copy]; stu2.name = @ "stu2" ; NSLog(@ "stu1 = %@" , stu1); NSLog(@ "stu2 = %@" , stu2); [stu2 release]; |
Person *p1 = [[Person alloc] init]; Person *p2 = [[Person alloc] init]; // 第一种方法 Class c1 = [p1 class ]; Class c2 = [p2 class ]; // 第二种方法 Class c3 = [Person class ]; NSLog(@ "c1 = %p, c2 = %p, c3 = %p" , c1, c2, c3); |
+ ( void )texst; |
+ ( void )test { NSLog(@ "调用了类方法test" ); } |
Class c = [p1 class ]; [c test]; |
- (id)init { // 1. 一定要调用回super的init方法:初始化父类中声明的一些成员变量和其他属性 self = [super init]; // 当前对象 self // 2. 如果对象初始化成功,才有必要进行接下来的初始化操作 if (self != nil) { // 初始化成功 _age = 10; } // 3. 返回一个已经初始化完毕的对象 return self; } |
// 输出当前函数名 NSLog(@ "%s\n" , __func__); // 输出行号 NSLog(@ "%d" , __LINE__); // NSLog输出C语言字符串的时候,不能有中文,可以使用printf函数输出 // NSLog(@"%s", __FILE__); printf ( "%s\n" , __FILE__); |
2014-12-08 244 浏览 1 回答
@ class Dog; @interface Person : NSObject // 人有一只狗,strong,强指针 @property (nonatomic, strong) Dog *dog; @end |
@implementation Person - ( void )dealloc { NSLog(@ "Person---- dealloc" ); } @end |
@ class Dog; @interface Dog: NSObject // 狗有一个主人,strong,强指针 @property (nonatomic, strong) Person *person; @end Dog.m: @implementation Dog - ( void )dealloc { NSLog(@ "Dog ---- dealloc" ); } @end |
Person *p = [[Person alloc] init]; Dog *d = [[Dog alloc] init]; // 第一种情况: // 当两个互指之后,会出现内存泄露,两个对象的dealloc没有被调用,也就是两个对象的内存没有被释放 p.dog = d; d.person = p; |
如图所示:
// 第二种情况: // 如果注释上面两行代码中的任意一行,两个对象都可以被释放 // 因为当main函数执行完毕之后,对象p和d都被回收,但是两个内存中的对象有强指针,不会被回收,所以会造成内存泄露 p.dog = d; // d.person = p; |
如图所示:
如果将Dog中的person属性改成weak:
@property (nonatomic, weak) Person *person; |
那么,上面第二种情况就变成了如下图所示:
这样的话,当程序运行结束,被回收的就是Person对象,既然Person对象被回收了,那么Dog对象就没有了强指针,也会被回收了。
ARC
ARC的判断准则:只要没有强指针指向对象,就会释放对象ARC的特点:1、不允许调用release、retain、retainCount2、允许重写dealloc,但是不允许调用[super deallo]3、@property的参数: * strong:成员变量时强指针,相当于原来的retain(适用于OC对象类型) * weak:成员变量时弱指针,相当于原来的assign(适用于OC对象类型) * assign:适用于非OC对象类型指针分两种:1、强指针:默认情况下,所有的指针都是强指针 __strong2、弱指针:__weakXcode是默认使用ARC的,如果某个.m文件真的不想使用ARC,可以通过以下步骤来不适用ARC:选择Xcode右侧项目树的根,然后是TARGETS -> Build Phases -> Compile Sources,下拉,选择目标.m文件,回车或者双击,弹出输入框,输入"-fno-objc-arc"回车,就可以了,如下图所示:如果开发环境是非ARC的,想要使用ARC的,将上面的"-fno-objc-arc"改成"-f-objc-arc"就可以了。
ARC循环引用当两端循环引用的时候,解决方案如下:1、ARC 1端用strong,另一端用weak2、非ARC 1端用retain,另一端用assign例如:在使用ARC下,有两个类:Person、Dog,如下:Person.h: