类的格式
类的声明和实现
.h文件格式
@interface 类名:NSObject{
# 成员变量
}
#属性
@end
.m文件格式
@implementation
# 方法的实现
@end
在声明或实现一个类的方式时,需要用“+”或“-”在方法开头
- “+”表示类方法
- “-”表示对象方法
类方法的调用
导入头文件,任何地方都可以通过类名调用类里面的方法:如[类名 类方法]
对象方法的调用
调用对象方法的时候,必须现有对象去调用它
如何创建一个对象
格式:[类名 new]
工程方法创建对象:Person *person = [Person person];
结构体
常用的结构体
CGSize;CGPoint;CGRect;NSRange
CGSize 宽高
CGSize size = {320, 480};
NSlog(@"%@",NSStringFromSize(size));
CGSize size = CGSizeMake(420,320);
NSLog(@"%@",NSStringFromSize(size));
CGPoint 定义一个点
CGPoint point = {320, 480};
NSlog(@"%@",NSStringFromPoint(point));
CGPoint point = CGPointMake(420,320);
NSLog(@"%@",NSStringFromPoint(point));
CGRect 定义一个点
CGRect point = CGRectMake{20, 20, 100, 200};
/*
struct CGRect{
CGPoint orgin;//坐标
CGSize size;//宽高
}
typedef struct CGRect CGRect;
*/
NSLog(@"%@",NSStringFromRect(rect));
NSRange 范围/幅度
/*
struct _NSRange {
NSInteger loction;//位置
NSInteger length;//长度
} NSRange;
*/
NSRange range = {2,5};
NSLog(@"%@",NSStringFromRange(range));
C语言的方法用在OC中时,不属于任何对象,声明即可使用
原子性
- atomic:原子性,中途写入中断,取消写入,写入失败
- nonatomic:非原子性,中途写入中断,写入多少算多少
C语言 判断字符串方法
-
isalpha()
是否为字母字符 -
isdigit()
是否为数字字符 -
isnumber()
是否为数字字符 -
isalnum()
是否为字母或数字字符 -
islower()
是否为小写字母 -
isupper()
是否为大写字母 -
toupper()
转为大写 -
islower()
转为小写
id
是一个泛型指针,可以指向任何一个指针,任何类型,任何对象
字符串
如何将C语言中的字符串转换成OC中的字符串
<1> 输入
char c[1000];
scanf("%s",c);
NSString *str = [[NSString alloc] initWithUTF8String:c];
<2> 转化
const char *P = "123123";
NSString *string = [[NSString alloc] initWithUTF8String:P];
NSString *string2 = [NSString stringWithUTF8String:P];
一段字符串在字符串中的位置和长度
NSString *str = @"00000111222333";
NSRange range = [str rangeOfString:@"1111"];
NSLog(@"1111在str里面的位置为%@",NSStringFromRange(range));
//若想输出“1111“所在的位置和长度
NSLog(@"%ld", range.location);// ->5
NSLog(@"%ld",range.length);// ->4
字符串的创建
1. 简单的创建
//初始化 NSString *str = [[NSString alloc] init];
// NSString *str = [NSString string];
// NSString *str = @"hello world";
2.字符串给字符串赋值
NSString *str1 = @"123456";
NSString *str2 = [[NSString alloc] initWithString:str1];
NSString *str3 = [NSString stringWithString:str2];
3. 通过拼接给字符串赋值
NSString *str1 = [[NSString alloc] initWithFormat:@"%ld%@", 1000, @"phone"];//str1:1000phone
NSString *str2 = [NSString stringWithFormat:@"%ld%@", 1000, @"phone"];//str2:1000phone
NSString *str3 = @"12345";
NSString *str4 = @"helloworld";
NSString *str5 = [NSString stringWithFormat:@"%@%@",str3, str4];
4. 从文件中读取
NSError *err = nil;
NSString *str = [[NSString alloc] initWithContentsOfFile:@"文件路径" encoding:NSUTF8StringEncoding error:&err];
if (err == nil) {
NSLog(@"文件f读取成功");
}else{
NSLog(@"文件读取失败");
}
//若想知道错误信息加上这表语句,localizedDescription方法会提取有用的信息
NSLog(@"错误信息为%@", [err localizedDescription]);
5. 通过URL路径获取字符串
NSString *urlPath = @"www.baidu.com";
//将字符串路径转成URL
NSURL *url = [NSURL URLWithString:urlPath];
NSError *err = nil;
NSString *str = [[NSString alloc] initWithContentsOfURL:urlPath encoding:NSUTF8StringEncoding error:&err];
if (err) {
NSLog(@"读取失败");
NSLog(@"%@", [err localizedDescription]);
}else{
NSLog(@"读取成功");
NSLog(@"str=%@", str);
}
字符串的方法:NSString类型
1. 字符串的拼接
每次拼接字符串都重新开辟一段空间
NSString *str1 = @"1000";
NSString *str2 = @"phone";
//1. NSString *str = [NSString stringWithFormat:@"%@%@", str1, str2];
//2. NSString *str = [str1 stringByAppendingString:@"hello"];
//3. NSString *str = [str1 stringByAppendingString:str2];
2. 字符串的搜索
NSString *urlPath = @"http://im.qq.com/qq=123";
NSRange range = [urlPath rangeOfString:@"qq="];
NSInteger loc = range.location;//位置:5
NSInteger length = range.length;//长度:3
3. 字符串的截取
NSString *str = @"0123456789";
NSString *str1 = [str substringFromIndex:5];//开区间(不包含边界的这个数)
NSLog(@"%@",str1);
//str里第5个位置开始之后的字符串全截取,即56789
NSString *str2 = [str substringToIndex:5];//闭区间(包含边界的这个数)
//只截取str里前5个字符,即01234
NSLog(@"%@",str2);
NSRange range = NSMakeRange(3, 2);
NSString *str3 = [str substringWithRange:range];//开区间
//截取str里第3个文职开始长度为2个的字符,即34
NSLog(@"%@",str3);
4. 字符串的比较
如果两个字符串的内容一样,那么内存只会开辟一块空间储存,是因为两个两个字符串的指针都指向同一块内存空间,如果字符串不一样,在内存里会有两块空间
NSString *str0 = @"abc";
NSString *str1 = @"abc";
NSString *str2 = @"abcb";
NSMutableString *str3 = [[NSMutableString alloc] initWithString:@"abc"];
NSLog(@"指针所指向对象的地址:%p",str0);
NSLog(@"指针所指向对象的地址:%p",str1);
NSLog(@"指针所指向对象的地址:%p",str2);
NSLog(@"指针所指向对象的地址:%p",str3);
//<1> 地址比较 通过==比较的是两个字符串的地址
if (str0 == str1) {//此时一样,地址内容都一样
//两个字符串地址一样
}else{
//两个字符串地址不一样
}
if (str0 == str3) {//此时地址不一样,虽然内容一样
//两个字符串地址一样
}else{
//两个字符串地址不一样
}
//<2> 内容比较
if ([str0 isEqualToString:str1] && str0 == str2) {//此时地址和内容都一样
//地址和内容都一样
}
//<3> compare方法比较
NSString *str0 = @"qqww";
NSString *str1 = @"abc";
NSComparisonResult result = [str0 compare:str1];
if (result == NSOrderedAscending) {
//前面一个字符串小于后面的字符串
}else if (result == NSOrderedSame){
//前面一个字符串等于后面的字符串
}else{
//前面一个字符串大于后面一个字符串
}
内容一样,地址不一定一样;
地址一样,内容一定一样
5. 字符串导入
NSString *str = @"床前明月光";
NSError *err = nil;
[str writeToFile:@"文件路径" atomically:YES encoding:NSUTF8StringEncoding error:&err];
if (err) {
//导入失败
}else{
//导入成功
}
获取字符串的长度
NSinteger length = [str length];
获取字符串中某一个位置的字符
unichar c = [str characterAtIndex:0];
查找前缀/后缀是否存在
BOOL isExistPrefix = [str hasPrefix:@"前缀"];
BOOL isExistSuffix = [str hasSuffix:@"后缀"];
将字符串转化成各种值
NSString *str0 = @"1440";
1. 转成int类型:int value = [str0 intValue];
2. 转成float类型:float value = [str0 floatValue];
3. 转成double类型:double value = [str0 doubleVlaue];
4. 转成NSInteger类型:NSInteger value = [str0 integerVlaue];
5. 转成longlong类型:long long value = [str0 longLongVlaue];
6. 转成BOOL类型:BOOL value = [str0 boolValue];
将一个字符串最前面的数字提取出来
NSString *str = @"10.1Qian 123phone";
double value1 = [str doubleValue];
NSLog(@"%f",value1);//10.100000
int value2 = [str intValue];
NSLog(@"%d",value2);//10
//字符串str前面的数字不为0,则为真,否则为假
BOOL isReal = [str boolValue];
NSLog(@"%d", isReal);//1
可变字符串的方法
创建初始化
NSMutableString *str = [[NSMutableString alloc] initWithCapacity:0];
[str setString:@"123"];//str = 123
可变字符串的拼接
NSMutableString *str = [[NSMutableString alloc] initWithCapacity:0];
[str appendString:@"12345"];//str = 12345
[str appendFormat:@"%@%d",@"456",567];//str = 1234545656
可变字符串的删除
NSString *str = @"I Love You";
NSMutableString *str1 = [[NSMutableString alloc] initWithString:str];
NSRange range =[str1 rangeOfString:@"Love"];//love的位置和长度
[str1 deleteCharactersInRange:range];//删除Love
//str = I You
可变字符串的替换和插入
这里的range承接自上面
[str replaceCharacterInRange:range withString:@"hate"];//I hate You
[str insertString:@" miss" atIndex:range.location + range.length];//str = I hate miss You
[str insertString:@"no" atIndex:5];//str = I hatnoe miss You
不可变数组的使用
字符串和数字混用(字符串分割后放到数组中)
NNString *str = @"I-love-you";
NSArray *array = [str componentsSeparatedByString:@"-"];//把str用“-”分割后存放于array中
NSArray *array = @[@"welcome", @"to", @"china"];
NSString *str = [array componentsJoinedByString:@" "];//把array用空格放到字符串str中形成一个字符串
创建数组
创建完了后,会给数组开辟一块空间,但是里面没东西,并且创建完了以后这块空间里面的东西不可被修改
NSArray *array0 = NSArray.new;
NSArray *array1 = [NSArray new];
NSArray *array2 = [[NSArray alloc] init];
NSArray *array3 = [NSArray array];
给数组添加对象,nil相当于C语言中的“\o”,平道nil后,nil后面的内容无效,下面数组实际指望里添加了两个对象
Person *person1 = [[Person alloc] init];
Person *person2 = [[Person alloc] init];
Dog *dog1 = [[Dog alloc] init];
NSArray *array1 = [[NSArray alloc] initWithObjects:person1, person2, nil, dog1];
//NNString、NSArray、NSDictionary正常来讲,每一个初始化方法都对应一个类方法,但NSArray里,有一个arrayWithObject的类方法,但初始化方法里面没有
NSArray *array2 = [NSArray arrayWithObject:person1];
通过数组创建数组
//对象方法
NSArray *tempArray = [NSArray arrayWithObjects:@"one", @"two", nil];
NSArray *array0 = [[NSArray alloc] initWithArray:tempArray];
//类方法
NSArray *array1 = [NSArray arrayWithArray:tempArray];
从文件里读取数组
**文件里面的数据必须按照一定得格式存储,否则没法读取**
NSArray *array = [NSArray arrayWithObjec:@"one", @"two", nil];
[array writeToFile:@"文件路径" atomically:YES];
NSArray *array1 = [[NSArray alloc] initWithContentsOfFile:@"路径"];//如果路径不存在,写失败,如果文件不存在,会创建一个新文件,并将数据写入,如果文件和路径都存在,直接写入
数组的遍历和简单使用
NSArray *array = @[@"one", @"123", @"你好"];
//1. 判断数组中元素个数
NSInteger arrayCount = [array count];
//2. 通过索引获取具体问之的对象
NSString *str = [array objectAtIndex:2];
数组遍历
1. for循环
for(NSInteger i = 0;i<[array count];i++)
{
NSString *tempStr = [array objectAtIndex:i];//或者:NSString *str = array[i];
NSLog(@"%ld:%@", i, tempStr);
}
2. 快速枚举
/* for(type *object in collection){...} */
//获取某一个对象具体的索引:-(NSInteger)indexOfObject:(id)anObject
for(id object in array){
NSInteger index = [array indexOfObject:object];
NSLog(@"快速枚举:%ld:%@", index, object);
}
3. block遍历
[array enumerateObjectUsingBlock:^(id obj, NSInteger idx, BOOL *stop){
NSLog(@"block-%ld:%@", idx, obj);
}];
重新description方法
- (NSString*)description{
NSString *des = [NSString stringWithFormat:@"age=%ld name=%@", self.age, self.name];
return des;
}
可变数组的使用
可变数组的初始化
1. NSMutableArray在初始化创建对象时,可以使用NSArray继承过来的方法,即
NSMutableArray *array = [[NSMutableArray alloc] init];
2. 下面2个方法是NSMutableArray自己扩充的方法,添加完对象后,可以往里面添加或删除对象
NSMutableArray *array1 = [[NSmutableArray alloc] initWithCapacity:0];
NSMutableArray *array2 = [NSMutableArray arrayWithCapacity];
3. 通过addObject:方法往数组里添加对象
[array addObject:@"one"];
4. 用removeObject:移除某一个对象
[array removeObject:@"hello"];
5. 交互数组里面2个对象的位置
[array exchangeObjectAtIndex:2 withObjectAtIndex:5];
6. 将一个数组添加到一个可变数组
NSMutableArray *mutArr = [NSMutableArray arrayWithObjects:@"one", nil];
NSArray *array = @[@"1", @"2"];
[mutArr addObjectsFromArray:array];
7.firstObject将数组里面的第1个对象取出来
NSString * strOne = [array firstObject];
8.lastObject获取最后一个对象
NSString *strLast = [array lastObject];
9. removeLastObject移除最后一个对象
[mutArr removeLastObject];
10. removeAllObjects 删除足足里面所有对象
[mutArr removeAllObjects]
11. 插入对象
[mutArr insertObject:@"123" atIndex:4];
可变数组的排序
NSMutableArray *array = [NSMutableArray arrayWithObject:@"123", @"234", nil];
for(int i = 0; i < [array count]; i++){
for(int j = 0; j < [array count] - i - 1; j++ ){
NSString *str1 = [array objectAtIndex:j];
NSString *str2 = [array objectAtIndex:j+1];
NSComparisonResult result = [str1 compare: str2];
if (result == NSOrderedDescending){
[array exchangeObjectAtIndex:j withObjectAtIndex:j+1];
}
}
}
NSLog(@"%@", array);
字典
字典初始化
1. 第一种创建方式
NSDictionary *dic0 = NSDictionary.new;
NSDictionary *dic0 = [NSDictionary new];
NSDictionary *dic0 = [[NSDictionary alloc] init];
NSDictionary *dic0 = [NSDictionary dictionary];
2. 字典里value-key配对出现的,可以通过key找到对应的value
NSDictionary *dic = [[NSDictionary alloc] initWithObjectAndKeys:@"175":@"height", @"150":@"weight", nil];
NSLog(@"%@", dic);//height = 175; weight = 250;
//通过字典里的key找到对应的值
NSString *height = [dic objectForKey:@"height"];
NSLog(@"height=%@", height);//height = 175
3. 通过字典穿甲字典
NSDictionary *dic4 = [[NSDictionary alloc] initWithDictionary:dic];
4. 通过两个数组创建字典
NSArray *values = @[@"175", @"小明"];
NSArray *keys = @[@"height", @"name"];
NSDictionary *dic5 = [[NSDictionary alloc] initWithObjects:values forKeys:keys]
5. 获取字典里所有的键值
NSArray *values = [dic allValues];
NSArray *keys = [dic allKeys];
可变字典
创建
NSMutableDictionary *mutableDic = [[NSMutableDictionary alloc] initWithCapacity:0];
一般用字符串作key,而value可以使任何对象
//1.字符串
[mutableDic setObject:@"123" forKey:@"string"];
//2.数组
NSArray *array =@[@"123", @"456"];
[mutableDic setObject:array forKey:@"array"];
//3.取出数组
NSArray *values = [mutableDic objectForKey:@"array"];//values = (123,456)
移除所有的键值对
[mutableDic removeAllObjects];
字典的遍历
[dic enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop){
NSLog(@"key = %@ value = %@", key, obj);
}];
集合NSSet
创建
//1.
NSSet *set0 = NSSet.new;
//2.
NSSet *set1 = [NSSet new];
//3.
NSSet *set2 = [[NSSet alloc] init];
//4.
NSSet *set3 = [NSSet set];
//5.
NSSet *set4 = [[NSSet alloc] initWithObjects:@"hello", @"world", nil];//{(hello,world)}
//6.
NSSet *set5 = [[NSSet alloc] initWithObjects:@"hello", @"hello", nil];//{(hello)} 数组可以放重复的东西,集合不可以
集合元素的个数
NSInteger count = [set5 count];//1个
是否存在,存在为1,不存在为0
BOOL isExist = [set5 containsObject:@"hello"]//1;
anyObject 随机从集合里取一个对象并返回
NSString *setString = [set4 anyObject];
NSLog(@"%@", setString);
//经打印几次都是同一个对象,但这个对象时随机的
点语法
car.brand:@"奥迪";//实际调用的是[car setBrand:@"奥迪";]
通过点语法调用set方法修改_brand的值
car.brand = @"BMW";//set方法,car.brand右边有"=",调用set方法
NSLog(@"%@", car.brand);//get方法,右边没有”=“,调用的get方法
NSInteger price = [car price];//get方法
NSInteger price = car.price;//点语法获取
总结
编写set方法和get方法时,set方法必须按照规范来写,才能通过点语法调用set方法,而get方法可以随便写,但是为了规范,get方法也得按规范写
//标准的set和get方法
[person setAge:15];//set方法
NSLog(@"age= %ld", [person age]);//get方法
//点语法
person.age = 51;//set方法
NSLog(@"age = %ld", person.age);
property和synthesize的使用
@property NSString *name;
//等价于
- (void)setName:(NSString*)name;
- (NSString*)name;
//声明时如果用`@property`,系统会自动展开标准的set和get方法
synthesize name = _name;
//等价于
- (void)setName:(NSString*)name{
_name = name;
}
- (NSString*)name{
return _name;
}
// @synthesize 会自动展开标准的set和get方法
synthesize详解
-
@synthesize name = _name
: name等于我们声明的全局变量_name -
@synthesize name
: 等价于@synthesize name = name
;虽然我们没有声明name的全局变量,但这么一写,会自动生成一个name的成员变量,但name因为并没有在头文件里声明,故私有的,而不是被保护的
继承
类别和扩展
在OC里面没有多继承,只有单继承,但可以用类别扩展实现
扩展:不能加成员变量,只能加方法
作用:能够给一些我们不嫌或不能修改的类添加方法,类别扩展,相当于这个类的父类。
类别扩展可以模拟实现多继承,我们可以为一个写好的A类添加一些方法,但不能添加成员变量,这个类可以继承他父类的成员变量和方法,他自己扩展的类别相当于这个类的继父,无法给这个类添加成员变量,但可以给这个类添加方法
public、protected、privite
- public:公有类,任何地方都可以访问
- protected:受保护的类,只有自己的类和子类可以访问
- privite:私有类,只有自己的类可以访问,子类不会继承父类
如果声明的全局变量,是@protected类型的可以被子类继承,如果只是通过@property和@synthesize来关联的成员变量,它是@private类的,不能被子类继承
重写,如果子类里面重写了父类里的方法,那么调用的是子类的方法,如果子类并未重写,则调用的是父类的方法
多态
A为父类,B类和C类继承自A类,都是A的子类,则写一个A类的函数,则B类和C类都可以调用
OC私有方法
声明全局变量时,若NSInteger_a 和_b都是@protected类,而NSInteger_add和_sub是@private类的,则写get和set方法时
@property (nonatomic, readwrite) NSInteger a;
@property (nonatomic, readonly) NSInteger b;
@property (nonatomic, readwrite) NSInteger add;
@property (nonatomic, readonly) NSInteger sub;
//nonatomic 是非原子性,atomic是原子性
- @atomic:能保证线程安全,同一个方法有可能同时有几个线程去访问,atomic能保证同时(某一时刻)只有1个线程在访问,atomic会消耗性能
- @nonatomic:虽然不能保证线程安全,但我们知道下面的属性访问时不会有多个线程同时访问,我们通常使用nonatomic
*readonly:只读方法
类的复合
Car类,Wheel类,Engine类都是集成自NSObject类
- 先写Wheel类和Engine,并重写各自的description方法
- 把Wheel类和Engine头文件导入Car类,则在Car类中可调用Wheel类和Engine类
内存管理
为什么要对内存进行管理?
及时硬件越来越强大,但是内存始终是有限的,如果不对其进行管理,内存会越积越多,最终导致程序崩溃
NSLog(@"dog:%@",dog);
打印dog描述信息,实际上打印的是对象的描述信息,但我们通常说dog就是对象,这是一个习惯性说法,实际上dog只是一个指向对象的指针,打印的时候直接写dog,实际上是给dog发送了一条description消息,直接打印dog等价于[dog description]
ReturnCount
OC里面new和alloc会开辟空间
C里面是malloc开辟空间,和malloc对应的有一个free(void*)
释放空间
MRC和ARC
ARC:不是Java里面垃圾回收机制,而是介于手动管理和垃圾回收机制之间的一种回收机制
MRC:手动管理,允许发送release消息,(消息就是函数,也叫方法)
内存泄露
如果我们不再使用一个对象,应该给这个对象发送release消息,发送消息就是让某个对象调用某个方法
例:
Dog *dog = [[Dog alloc] init];
//如果没有[dog release];那么dog就有内存泄露
僵尸对象
僵尸对象:一个对象已经不存在了,但是我们还给先前指向这个对象的指针发送消息,这时候会崩溃
例:
Dog *dog = [[Dog alloc] init];
[dog release];
NSLog(@"dog=%@", dog);
当出现僵尸对象时,控制台会打印虾米的信息,意思是Dog这个创建的对象已经被release了,deallocation就是被释放的意思-[Dog respondsTOSelector:]message sent to dealloction instance xxx
过度释放
Dog *dog = [[Dog alloc] init];
[dog release];
[dog release];//过度释放,一个alloc只能对应一个release,过度释放会导致崩溃
@class name; #import "name"
通过@class这个关键词告诉这个头文件,哪有这么一个类,如果通过#import这种方式导入,可能会出现循环导入,导致编译没法通过
在.h文件通过@class告诉A类有B类存在,但是.m文件还是要将B.h头文件导入进来,方能使用
reation和release
reation:使对象拥有使用权,使retainCount+1
release:释放使用权,使retainCount-1
alloc和dealloc
alloc:开辟一段内存空间
dealloc:对应alloc,当retainCount=1时,再次给对象发送release消息时,就会调用dealloc函数,将对象的空间释放掉
- (void)delloc{
NSLog(@"%@", __func__);
[super delloc];
}
这是我们重新的父类的-(void)delloc
函数,系统会自动的去调用,我们不能手动去调用它
set和get的标准写法
以Car类为例,把Car在Person.h里@class下,再把Car.h导入Person.m里
- (void)setCar:(Car*)car{
if(_car != car){//判断的是地址不一样
[_car release];//先给上一个_car发送release消息
_car = [car retain];
}
}
- (Car*)car{
return _car;
}
在一个类里如果有全局变量的指针,定义为全局变量的指针后,马上从-(void)delloc
函数里给它发送release,如果这个指针始终为nil,那么发送的release不起任何作用
自己创建的类重写NSCopying和NSMutableCopying协议里的方法
//NSCopying协议里的方法
- (id)copyWithZone:(NSZone*)zone{
A *a = [[A alloc] init];
return a;
}
- (id)mutableCopyingWithZone:(NSzone*)zone{
A *a = [[A alloc] init];
return a;
}
Property内存管理
assign
直接赋值,主要用在基本数据类型,引用计数不变,指针指向同一个地址
什么情况下需要release?
有alloc、new、retain、copy、mutableCopy的情况下都需要release或autorelease
什么情况下载dealloc里面给对象发送release?
如果对象时全局变量,就在dealloc发送release消息,全局的变量必须在dealloc里面发送release,因为全局变量在整个类里面任何方法里面都可以使用,如果在对象被销毁之前,就将此全局变量销毁,调用的时候就在发送崩溃
如果一个对象是在函数里面的局部变量,这个指针使用完后,如果不再使用,马上发送release消息
如果想对一个对象copy或者发送mutableCopy消息,应该怎么做?
分两种情况:
- 系统类:如NSString、NSArray等,这种系统类创建的对象直接可以copy或者发送mutableCopy,因为这些系统类已经采用NSCopying、NSMutableCopying这两个,并且实现了这个两个协议里面的方法
- 自己创建的类:这种情况下,需要我们自己采用NSCopying、NSMutableCopying这俩协议,并且实现这俩协议里面的方法,如果不采用协议,或者采用了协议里面的方法,没法copy或者mutableCopy,会崩溃
NSString、NSArray、NSDictionary里copy,retain和mutableCopy
- 系统类里面的不可变字符串,不可变数组,不可变字典,使用retain和copy效果是一样的,即不可变的字符串、数组、字典使用copy和retain都属于浅拷贝,只有mutableCopy才是深拷贝
- 在类的声明时,写retain和copy效果一样,但习惯于写copy
- 不可变的字符串、数组、字典甚至我们自己创建的类,以后都不能用引用计数来作为依据,什么时候该示范对象,什么时候不该释放对象,引用计数知识一个原理,但系统的实现我们并不清楚,以后只需要按照黄金法则来使用即可
黄金法则
- 以后给指针赋值时,只有有alloc、new、mutableCopy,retain,只有有这些关键词,我们就需要再适当的时候给这些对象(指针)发送release,释放使用权
- 全局变量统统在dealloc里面发送release消息;局部变量什么时候不用,立即发送release消息即可