Objective-C语法

一、OC简介

《Objective-C语法》 OC_类与对象.png

Objective_C简称OC,是 C语言的超集(兼容 C 的代码)
OC是扩充自C语言的面向对象编程语言
面向对象编程:OOP (Object Oriented(面向) Programming)
面向对象特点包括:封装 、继承 、多态
面向对象 与 面向过程 :是两种不同的编程思想

类和对象

流程:定义类—>创建对象—>使用对象
类:具有相同特征或行为的事物的抽象
对象:就是类的实例(类是对象的类型)

1.定义类

类的定义:

①接口部分:对外声明类的特征和行为 // 接口部分和实现部分要分开写
标识: @interface…@end
包含内容:类名、父类名、实例变量、方法等
②实现部分:对内实现行为
标识:@implementation…@end
包含内容:实现方法 即实现类的行为

.h文件(接口文件或头文件)
@interface person/*类名*/ : NSObject/*父类名*/{
@public    //实例变量(特征)    
NSString *_name;  //姓名    
NSString *_sex;   //性别    
NSString *_hobby; //兴趣    
int      _age;   //年龄
}
/************方法(行为部分)************/
- (void)sayHi;- (void)eat;
@end
.m文件(实现文件)
@implementation person//实现方法(实现行为)
- (void)sayHi{    NSLog(@"你好,我叫%@,今年%d岁,喜欢%@",_name,_age,_hobby);
}
- (void)eat{  
  NSLog(@"我要去吃饭");
}
@end
2.创建对象
①分配内存空间:根据类中声明的实例变量为对象分配内存,将所有实例变量置为默认值0,并返回首地址
            person *p = [person alloc];  
②初始化:为对象的实例变量设置初始值
            p = [p init];
以上两步可写在一起: person *p = [[person alloc]init];

+(id)alloc; +号表示这个方法属于类,只能类执行。id返回值类型,表示任意类型的对象,即创建好的对象
-(id)init;    -号表示这个方法属于对象,只能对象执行。id返回值类型,表示初始化完成的对象

子类可以重写父类的方法:

《Objective-C语法》

二、实例变量可见度和方法

实例变量的可见度:

@public(公有的) :实例变量可以在类的外部和内部操作
@protected(受保护的,默认的) : 实例变量只能在该类和其子类内操作
@private(私有的) : 实例对象只能在该类内访问

方法:

①类方法:只能类使用 例:+(id)alloc 注:类方法不能使用实例变量
②实例方法:只能对象使用,例如:-(void)sayHi

例:- (void)replaceObjectAtIndex:(NSUInteger)index withObject:(id)anObject
包括:方法类型标示符,返回类型 ,参数形容词:参数类型,参数名
“ : ”标识参数不能省略。由冒号必须有参数

③方法使用:

[people sayHi];  给people发送sayHi消息,或者使用点语法 people.sayHi;
1.setter:设置器(为实例变量赋值的方法)
如果一个实例变量是 int age 或者 _age.
setter书写格式:-(void)setAge:(int)age;(忽略下划线)
//传参时有几个冒号 ,就是传几个参数
2.getter:访问器(读取实例变量值的方法)
getter书写格式:-(int)age;(忽略下划线)
注意:无论是setter还是getter,内部操作都是实例变量,(每个实例变量都需要一对setter和getter方法)
3.自定义初始化方法:
-(id)initWithName:(NSString *)name sex:(NSString * )sex;
类的引用:
#import :导入头文件
#import “”导入自定义类
#import <>导入类库中的头文件
// 类似于C语言中的 #include  但是可以避免头文件重复导入
@class:
告诉编译器@class后的字符串作为类名使用,并未导入类的接口内容
有效避免嵌套循环导入

三、继承、初始化、遍历构造器

《Objective-C语法》 继承.初始化.便利构造器.png

1.继承:父类 、子类

①继承是单向的,不可相互继承
②传递性:A继承于B,B继承于C,则A 同时具有 B和C的特征和行为
③子类可以继承父类全部的特征和行为(也可具备部分特征或行为)//@private标识的父类特征 不能被继承
④OC中只允许单继承(即每个类只能有一个父类)
⑤没有父类的类称为根类。OC中基类是NSObject(祖宗)
⑥继承的内容:所有实例变量和方法
⑦如果子类不满意父类方法的实现,可以重写父类的方法。

2.初始化方法

两步:①开辟空间alloc ②初始化init
作用:为某些实例变量赋初值
初始化方法在对象的整个生命周期里只是用一次

3.super 编译器指令,并非对象

作用:给super发消息,可以执行父类中实现的方法
子类可以重写父类的方法,即子类既有自己的实现,又有父类继承下来的实现,如果想使用父类的实现,向super发送消息
完整初始化方法:

@implementation Student
- (instancetype)init{
    //给super发送init消息,即执行父类中实现的init方法
    self = [super init]; 
    if (self) {   
      //初始化设置
      }
     return self; //返回初始化完成的对象
}

//便利构造器:(+方法)
//封装了alloc和初始化方法,使用起来更加简洁
+(instancetype)girlFriendWithName:(NSString *)name gender:(NSString *)gender age:(NSInteger)age{
GirlFriend *g = [[GirlFriend alloc]initWithName:name  gender:gender age:age];
return g;
}

四、字符串、数组

#pragma mark ------------- NSString -----------
#pragma mark赋值
   NSString*s1 =@"123";
   NSLog(@"s1 = %@",s1);

#pragma mark初始化方法
   //一般初始化
   NSString*s2 = [[NSString alloc]initWithFormat:@"%@今年%@岁",@"小明",@"18"];
   NSLog(@"s2 = %@",s2);
   //便利构造器初始化
   NSString*s3 = [NSString stringWithString:s2];
   NSLog(@"s3 = %@",s3);
   NSString*s4 = [NSString stringWithFormat:@"%@你好",@"美女"];
   NSLog(@"s4 = %@",s4);
   
#pragma mark通过文件路径获取文件中的字符串
   NSString*s5 = [NSString stringWithContentsOfFile:@"/Users/王胜利/Objective_C/OC_课堂及作业/OCLesson4_课后/OCLesson4_课后/1.txt"encoding:NSUTF8StringEncodingerror:nil];
   NSLog(@"s5 = %@",s5);
   //usedEncoding :表示不知道编码方式 写nil

#pragma mark length
   NSUIntegerui = [s5 length];
   NSLog(@"lenthOfs5 is %lu",ui);
   
#pragma mark前后缀
   BOOLb1 = [s4 hasPrefix:@"美女"];//判断前缀
   BOOLb2 = [s4 hasSuffix:@"约么"];//判断后缀
   NSLog(@"前缀%d,后缀%d",b1,b2);
   
#pragma mark大小写转换
   NSString*s6 =[s5 capitalizedString];
   NSLog(@"首字母大写:%@",s6);
   NSString*s7 = [s6 uppercaseString];
   NSLog(@"所有字母大写:%@",s7);
   NSString*s8 = [s7 lowercaseString];
   NSLog(@"所有字母小写:%@",s8);
   
#pragma mark比较字符串大小
   NSComparisonResult b3 = [s6 compare:s7];
   NSLog(@"compareResult = %ld",b3);
   
#pragma mark判断字符串是否相等
   BOOLb4 = [s6 isEqualToString:s8];
   
#pragma mark 获取某个index的字符(遍历)
   NSLog(@"%c",[s6 characterAtIndex:3]);

#pragma mark截取字符串
   NSString*s9 = [s6 substringFromIndex:3];//截取index = 3往后的内容(包含index = 3)
   NSString*s10 = [s6 substringToIndex:2];//截取到index = 2(不包含index = 2)
   NSString*s11 = [s6 substringWithRange:NSMakeRange(5,4)];//从index = 5开始截取4个字符
  
#pragma mark ----------NSMutableString---------
   //NSMutableString 继承于NSString 上面NSString方法NSMutableString同样适用
   NSMutableString*mS1 = [[NSMutableString alloc]initWithFormat:@"abc123"];

#pragma mark改
    [mS1 setString:@"ABC123"];

#pragma mark拼接
    [mS1 appendString:@"def"];

#pragma mark 替换掉某一范围的字符串
    [mS1 replaceCharactersInRange:NSMakeRange(3,3) withString:@"456"];

#pragma mark删除
    [mS1 deleteCharactersInRange:NSMakeRange(3,3)];
   
#pragma  mark插入
    [mS1 insertString:@"hijk"atIndex:5];



#pragma mark ---------------NSArray----------------
#pragma mark初始化方法
   NSArray*a1 = [[NSArray alloc]initWithObjects:@"1",@"2",@"3",nil];
   //便利构造器
   NSArray*a2 = [NSArray arrayWithObjects:@"4",@"5",@"6",nil];
   NSArray*a3 = [NSArray arrayWithArray:a2];
   //字面量(语法糖)
   NSArray*a4 =@[@"a",@"b",@"c"];

#pragma mark获取元素个数
   NSUInteger ui1 = [a1 count];
   
#pragma mark取出元素下标
   
   NSUInteger ui2 = [a4 indexOfObject:@"b"];
   
#pragma mark根据下标取出下标所有的元素
   NSString*s = [NSString stringWithString:[a4 objectAtIndex:2]];
   
#pragma mark -----------NSMutableArray-----------
   NSMutableArray*mA =[NSMutableArray arrayWithArray:a1];
   
#pragma mark 增加元素
    [mAaddObject:@"4"];
   
#pragma mark 删除元素
    [mA removeLastObject];
    [mA removeObjectAtIndex:2];
   
#pragma mark插入元素
    [mAinsertObject:@"3"atIndex:2];
   
#pragma mark替换
    [mA replaceObjectAtIndex:2withObject:@"a"];
   
#pragma mark -------------NSNumber-----------
   inti =2;
   NSNumber*_i = [NSNumber numberWithInt:i];//将int基本数据类型转换成对象类型
   [_i stringValue];//将对象类型 转换成 字符串
   
   inta = [_i intValue];//将对象类型转换成基本数据类型

五、 字典、集合

《Objective-C语法》 NSDictionary NSSet.png

1 .NSDictionory字典

定义:字典是用于保存具有映射关系(key – value对)数据的集合
特征:
①key- value 在 dictionary中认为是一个条目(Entry)
②key不能重复,value必须是对象
③键值对在字典中是无序存储的
NSDictionary不可变字典:
字典一旦创建,键值对就无法改变,不可添加,不可删除, 只读

2.NSMutableDictionary可变字典:

可以对字典进行 <增><删><改> 操作

3.NSSet集合

特征:
①集合中元素唯一
②存储的数据是无序存储
③存储元素必须是对象类型

NSSet:
NSMutableSet:
NSCountedSet:

  1. 集合类型的快速枚举
    快速枚举:
    for(<#type*object#> in <#collection#>){ }
    ①object是遍历得到的元素对象
    ②collection是集合类型的对象:数组,字典,集合.
    特点:
    ①数组枚举得到数组中的元素对象
    ②字典枚举得到字典中的key值
    ③集合枚举得到集合中的元素对象

2.数组排序

  • (NSArray *)sortedArrayUsingSelector:(SEL)comparator;
  • (void)sortUsingSelector:(SEL)comparator;

六、 Block

《Objective-C语法》 block.png

代码块本质上是和其他变量类似。不同的是,代码块存储的数据是一个函数体。使用代码块是,你可以像调用其他标准函数一样,传入参数数,并得到返回值。

脱字符(^)是块的语法标记。按照我们熟悉的参数语法规约所定义的返回值以及块的主体(也就是可以执行的代码)。下图是如何把块变量赋值给一个变量的语法讲解:

《Objective-C语法》

按照调用函数的方式调用块对象变量就可以了:int result = myBlock(4); // result是 28

1.参数是NSString*的代码块
void (^printBlock)(NSString *x);  
printBlock = ^(NSString* str)  {  
    NSLog(@"print:%@", str);  
};  
printBlock(@"hello world!");  

运行结果是:print:hello world!

2、代码用在字符串数组排序
NSArray *stringArray = [NSArray arrayWithObjects:@"abc 1", @"abc 21", @"abc 12",@"abc 13",@"abc 05",nil];  
NSComparator sortBlock = ^(id string1, id string2)  {  
    return [string1 compare:string2];  
};  
NSArray *sortArray = [stringArray sortedArrayUsingComparator:sortBlock];  
NSLog(@"sortArray:%@", sortArray);  

运行结果:sortArray:(
** “abc 05”,**
** “abc 1”,**
** “abc 12”,**
** “abc 13”,**
** “abc 21″**
)

3、代码块的递归调用

代码块想要递归调用,代码块变量必须是全局变量或者是静态变量,这样在程序启动的时候代码块变量就初始化了,可以递归调用

static void (^ const blocks)(int) = ^(int i)  {  
    if (i > 0) {  
        NSLog(@"num:%d", i);  
        blocks(i - 1);  
    }  
};  
blocks(3);  

运行打印结果:
num:3
num:2
num:1

4、在代码块中使用局部变量和全局变量

在代码块中可以使用和改变全局变量

int global = 1000;  
int main(int argc, const char * argv[])  {  
    @autoreleasepool {  
        void(^block)(void) = ^(void)  {  
            global++;  
            NSLog(@"global:%d", global);  
        };  
        block();  
        NSLog(@"global:%d", global);  
    }  
    return 0;  
}  

运行打印结果:
global:1001
而局部变量可以使用,但是不能改变。

int local = 500;  
void(^block)(void) = ^(void)  {  
    local++;  
    NSLog(@"local:%d", local);  
};  
block();  
NSLog(@"local:%d", local);  

在代码块中改变局部变量编译不通过。怎么在代码块中改变局部变量呢?在局部变量前面加上关键字:__block

__block int local = 500;  
void(^block)(void) = ^(void)  {  
    local++;  
    NSLog(@"local:%d", local);  
};  
block();  
NSLog(@"local:%d", local);  

运行结果:local:501

七、 时间日期

《Objective-C语法》 类的扩展.png

1. NSDate
NSDate *date = [NSDate date];//初始化  获取0时区现在日期时间

NSTimeZone *zone = [[NSTimeZone alloc]init]; zone = [NSTimeZone localTimeZone];//获取本地时区

NSInteger offest = [zone secondsFromGMT];//获取本地时区和0时区的时间差  (以 分钟 算)

NSTimeInterval subTime = [date1 timeintervalSinceDate: date2];//计算两个日期的时间差
2. NSDateFormatter
//作用:iOS中的时间日期格式类  用于实现NSString和NSDate的互相转化 
NSDateFormatter *formatter = [[NSDateFormatteralloc]init];
[formatter setDateFormat:@"yyyy年MM月dd日 HH点mm分ss秒"];
[formatter setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:8]];
// 1.将日期转换成字符串输出
NSString *date1 = [formatter stringFromDate:[NSDate date]];
NSLog(@"%@",date1);
NSString *s = @"2014年05月01日 10点23分18秒";
// 2.将字符串转换为日期
NSDate *date2 = [formatter dateFromString:s];
NSLog(@"%@",date2);

苹果系统内部,时间是以零时区为基准存储
默认情况下
stringFormDate:(把日期转换成字符串显示) 系统会自动 算 零时区时间加上 时区差(GTM) 的时间显示
dateFromString:(把时间字符串转换成日期) 系统存储零时区时间,,默认会把我们输入的时间减去 时区差(GTM)存储在系统中
使用 NSDateFormatter 时 格式化格式 还有时区

3. Category 类目
  1. 为没有源代码的类添加方法
  1. 添加的类会成为原类的一部分 可以被继承
4. Extension 类的延展

为自定义类定义”私有的”方法 外部不可访问

两种定义方法:

  1. 定义一个 Extension 文件 只有.h文件 在里面添加 方法
  2. 在需要的类的.m 文件上面 添加 @Interface 类名() 方法名 @end
5. Protocol 协议

就是一套标准(一堆方法声明),,只有.h文件
在接受协议的对象的类的.m中实现协议中定义的方法

关键字:
@required 默认的,方法 代理必须实现
@optional 可以选择实现,,也可以不实现

遵守协议步骤:

  1. 在类的.h文件 父类名后写上<协议名>
  2. 在.m文件中实现协议中的方法

delegate 代理

Protocol 的核心使用场景是实现delegate设计模式

八、属性

《Objective-C语法》 属性.png

1.属性 @property

为实例变量提供了setter getter 方法的默认实现

.h文件中 @property 声明了两个方法 (setter getter)
.m文件中 使用@synthesize实现属性

注意:使用@property声明属性 可以省略 @synthesize和实例变量

2.属性的属性 attribute
//1.读写设置
//读写性控制:readwrite 读写  (默认设置) 即声明setter  又声明getter
@property(readwrite) NSString *name;

//readonly 只读 只声明getter方法
@property(readonly) NSString *sex;

//setter  给getter重命名
@property(getter= fun1)NSString * address;

//getter  给setter重命名
/*自定义方法名后面加冒号 (setter有参数)*/
@property(setter=setPhoneNum:)NSString *phoneNum;

//2.原子能设置
//原子性控制atomic (默认设置)  setter getter内部做了多线程访问处理,多线程访问下比较安全   (缺点:暂用系统线程资源,单线程下不建议适用)
@property(atomic)NSString *hobby;

//nonatomic : setter getter内部没有做多线程访问处理,,(程序通常使用nonatomic,只有当属性需要线程安全是,才定义 atomic)
@property (nonatomic)NSString *job;

//3.类型设置
//语义设置assign  :(在setter getter 内部直接复制)当属性是非对象类型(int float 等基本数据类型)时使用
@property (nonatomic ,assign)NSInteger age1;

//retain : setter getter 内部会做内存优化  (当属性是对象时使用)
@property (nonatomic ,retain)NSString *name1;

//copy : 同 retain 一样,setter getter内部会做内存优化,,,但是copy遵循(NSCopying协议) 当属性是对象类型,并且想要得到参数时,使用copy 关键字
@property(nonatomic ,copy)NSString *address1;

// 4.点语法(配合setter getter  或者属性一起使用)
SingleDog *sdog1 = [[SingleDog alloc]init];    [sdog1 setName:@"zhangsan"];
    [sdog1 name];
// 直接使用点语法赋值 (只要有setter getter方法)
    sdog1.name = @"lisi";    NSLog(@"%@",sdog1.name);       sdog1.gender = @"nan";
    NSLog(@"%@",sdog1.gender);

//5.KVC(Key - Value - Coding) 键值编码
是一种间接访问实例变量的方法
key : 键 (用于标识实例变量)
value : 实例变量的值
①//使用KVC给实例变量赋值
//类似于setter方法
[sdog1 setValue:@"wangwu" forKey:@"name"];
   
//获取值
//类似于getter方法
NSLog(@"%@",[sdog1 valueForKey:@"name"]);

//②KVC可以给私有变量(@private修饰的实例变量)赋值和取值  (key不能写错,字符串匹配)
[sdog1 setValue:@"dasfafa" forKey:@"phoneNum"];
//③ 当key不存在的时候,系统会执行setValue:forUndefinedKey: 
//然后抛出一个异常,但是 该方法只与 setValue:ForKey搭配使用

//注意:一般从网络上请求下来的数据,一般都是数组套字典,字典套数组之类的,直接用KVC去取值赋值这时候一定要加上 setValue :forUndefinedKey这个方法(防止崩溃)
//④setValue:forKeyPath使用点语法 ,,引用路径 设置或输出值
Pig *p1 = [[Pigalloc]init];
Food *f1 = [[Foodalloc ]init];

[p1 setValue:f1 forKey:@"food"];
[p1 setValue:@"白菜" forKeyPath:@"[food.name](http://food.name/)"];

NSLog(@"%@",[p1 valueForKeyPath:@"[food.name](http://food.name/)"]);
NSLog(@"%@",[f1 valueForKey:@"name"]);

//⑤setValue:ForKeysWithDictionary借用字典同时设置读取多个key 和 value

NSMutableDictionary *dic1 = [NSMutableDictionarydictionary];
NSDictionary *dic2 =[NSDictionary dictionaryWithObjectsAndKeys:@"zhaoda",@"name",@"nan",@"gender", nil];
   
[dic1 setValuesForKeysWithDictionary:dic2];
NSLog(@"%@",dic1);
   
[sdog1 setValuesForKeysWithDictionary:dic2];
NSLog(@"%@  %@",sdog1.name,sdog1.gender);

九、内存管理初级

《Objective-C语法》 OC_内存管理低级.png

iOS应用出现 Crash(闪退) ,90%原因是因为内存问题
//主要有 :内存溢出 野指针异常 过早释放等
//垃圾回收(gc):java 里的内存管理机制(程序员只负责开辟,由系统自己判断哪些空间不再使用并收回)

OC中的两种内存管理方式:
MRC:(Manual Reference Count)手动引用计数
内存的开辟和释放都是有程序代码进行控制.(对程序员要求较高)
ARC:(Auto Reference Count)自动引用计数
iOS 5 之后新加的编译器特性,程序员只负责开辟空间,不用去释放

// ARC的本质还是MRC,只是编译器加了自动释放的代码

C语言中
:使用malloc和free 进行堆内存的创建和释放,,堆内存只有使用和销毁两种状态
OC中
:引用引用计数机制来管理内存(多个指针同时放问一款内存)当一个新的引用指向对象时,引用计数器就递增,当去掉一个引用时,引用计数就递减.当引用计数到零时,该对象就将释放占有的资源

影响引用计数的方法:

1.alloc:开辟内存空间 引用计数从0到1
Person *p1 = [[Person alloc]init];

2.retain:引用计数 + 1
Person*p2 = [p1 retain];
//实际开发中不用
//注意:当使用retain是若不找另一个指针子向它,则会出现内存泄露问题

 retainCount方法:获取当前对象的引用计数.
NSLog(@"%lu",[p1 retainCount]);
//注意:1.实际开发中 retainCount不要用  2.即使要用也只能用在自定义的类上

3.copy :将某一内存区域的内容拷贝一份,拷贝到新的内存空间中,(被拷贝的引用计数不变,新的内存区域引用计数为1)

4.release:引用计数 -1 
//当一个对象用完之后,要用 release 或者 autoRelease 去释放
//release 到0之后不能再继续 release 过度释放也会崩溃

5.dealloc:销毁对象
他是继承自父类的方法,当引用计数为0的时候,由对象自动调用
//一般我们要在类的.m文件中重写一下dealloc方法,,把我们声明的属性也销毁

- (void)dealloc{
//[_age release];//assign
修饰非对象类型,,没有对引用计数产生影响,,,无需释放

    [_name release];
//对象销毁了,
属性没有用,也要销毁
    [_gender release];   
NSLog(@"%@被销毁",self);    
[super dealloc];
}

6.autorelease:在未来的某一时刻引用计数 -1.
autorelease对象的释放收 autoreleasepool 的控制
NSAutoreleasePool*pool = [[NSAutoreleasePool alloc]init];

Person*p6 = [[Person alloc]init];
[p6 retain];
[p6 autorelease];
NSLog(@"++++%lu",[p6 retainCount]);
[pool release];

NSLog(@"====%lu",[p6retainCount]);

// 从开辟空间初始化autoreleaepool对象,到pool对象被release 就相当于@autoreleasepool加上{}

//但自iOS 5之后推荐使用    @autoreleasepool { }

//@autoreleasepool { }出了大括号,自动释放池才向各个对象发送release消息

//如果使用了@autoreleasepool{} ,,,自动释放池是一种栈的结构
总之,凡是使用了alloc retain copy 让内存的引用计数增加了,就需要使用release或者autorelease让内存的引用计数减少,在一段代码内,增加和减少的次数要相等

copy方法 :
**一个对象想要copy,生成自己的副本,需要遵守NSCopying协议,定义copy的细节,,(如果类没有接受NSCopying协议而给对象发送copy消息,会引起carsh)**

.h文件
@interfacePerson :NSObject<NSCopying>//手动添加遵守NSCopying协议

@property(nonatomic,copy)NSString*name;

@end

.m文件
@implementation Person
- (void)dealloc{    
   [_name release];   
   NSLog(@"销毁");   
   [super dealloc];
}
//- (id)copyWithZone:(NSZone *)zone{
//    //[self retain]把引用计数+1
//    return [self retain];
//    //浅拷贝相当于只拷贝了指针  (retain只不过它遵循了NSCopying协议)
//}
- (id)copyWithZone:(NSZone*)zone{   
Person*p = [[ Person alloc]init];    
p.name=self.name;   
return p;   
//深拷贝新建了一个对象,并将对象return出去
//真正意义上得拷贝,他开辟了一个新的空间对象也return了出去
}

@end

main.m文件
Person*p1 = [[Person alloc]init];       
Person*p2 = [p1 copy];       
NSLog(@"%p",p1);       
NSLog(@"%p",p2);
NSLog(@"%lu",[p1 retainCount]);
NSLog(@"%lu",[p2 retainCount]);

打印结果

《Objective-C语法》 打印结果

十、内存管理高级

《Objective-C语法》 OC_内存管理高级.png

属性内部实现

assign:
- (NSInteger)age{
    return _age;
}
- (void)setAge:(NSInteger)age{
    _age = age;
}
retain:
- (NSString *)name{
    return [[_name retain] autorelease];
}


- (void)setName:(NSString *)name{
    if (_name != name) {
        [_name release];
        _name = [name retain];
    }
}

copy:
- (NSString *)gender{
    return [[_gender retain]autorelease];
}
- (void)setGender:(NSString *)gender{
    if (_gender != gender) {
        [_gender release];
        _gender = [gender copy];
    }
}
delloc://由系统自动调用,,永远不要自己手动调用
- (void)dealloc{
    [_name release];
    [_gender release];
    [super dealloc];//最后一定要调用父类的delloc方法
}

便利构造器的内存管理
+(instancetype)personWithName:(NSString *)name Age:(NSInteger)age Gender:(NSString *)gender{
   Person *p =  [[Person alloc]initWithName:name Age:age Gender:gender];
//  [p release];//release 写在上面,下面return是,,p就成了野指针
//  return p;
//  [p ralease];//release写在下面,,会出现内存泄露
    return [p autorelease];
}
//如果是便利构造器声明的对象,无需释放,因为便利构造器内部谢了autorelease方法,,出了花括号自动释放

Collection(NSArray等容器类)的内存管理

  • 加入collection的对象会被retain
  • 移除collection的对象会被release
  • collection被释放时,会对内部所有对象release
多态:

父类指针可以指向子类对象

    原文作者:MI移动
    原文地址: https://www.jianshu.com/p/20b8ea623bf4
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞