一、ARC
简介:ARC是自ios 5 之后增加的新特性,完全消除了手动管理内存的繁琐,编译器会自动在适当的地方插入retain、release、autorelease语句。你完全不需要担心内存,因为编译器为你处理了一切。
ARC 是编译器特性吗,而不是ios运行时的特性,它也不是类似于其他语言中的垃圾收集器。因为ARC 和手动内存管理性能是一样的,有时还能更加快速,因为编译器还可以执行某些优化。
ARC判断准则:只要没有强指针指向的对象,就会释放对象。
指针分两种:
1.强指针:默认所有实例变量和局部变量都是Strong指针;
2.弱指针:指向的对象被回收后,弱指针会自动变为nil指针,不会引发野指针
错误。
ARC特点:
1.不能调用release、retain、autorelease、retainCount;
2.可以重写dealloc,但是不能调用[super dealloc];
3.@property参数:
*strong:成员变量是强指针(适用于OC对象);
*weak:成员变量是弱指针(适用于OC对象);
*assign:适用于非OC对象类型;
4.以前的retain改为strong。
ARC循环引用解决方案:一端用strong;一端用weak。
二、Block
作用:用来保存一段代码。苹果官方建议尽量多用block。在多线程、异步
任务、集合遍历、集合排序、动画转场用的很多。
block标志: ^ .
block和函数很相像:
1.可以保存代码;
2.有返回值;
3.有形式参数;
4.调用方法一样。
注:block还可以作为函数参数或者函数的返回值。
block定义:
int (^MySum)(int, int) = ^(int a, int b)
{
return a+b;
};
定义了一个叫MySum的blocks对象,它带有两个int参数,返回int。等式右边就是blocks的具体实现.
调用block: int c = MySum(10,11);
Block可以访问局部变量,但是不能修改。
int sum = 10;
int (^MyBlock)(int) = ^(int num)
{
sum++;//编译报错
return num * sum;
};
如果要修改就要加关键字:__block
__block int sum = 10;
Block和指向函数的指针的比较:
1.定义函数指针:
int (*myFn)();
定义Block:
int (^MyBlocks)(int,int);
2.调用函数指针:
(*myFn)(10, 20);
调用Block:
MyBlocks(10, 20);
使用typedef定义block类型:(参考typedef指向函数的指针)
(1)typedef int(^MyBlock)(int,int);
MyBlock sumBlock = ^(int a,int b)
{ return a+b; };
(2)MyBlock minusBlock;
minusBlock = ^(int a,int b)
{ return a-b; };
三、protocol(协议)
基本用途:
1.可以用来声明一大堆方法(不能声明成员变量);
2.只要某个类遵守了这个协议,就相当于拥有这个协议中所有的方法声明;
3.只要父类遵守了某个协议,就相当于子类也遵守了。
协议的声明类似于类接口的声明,有一点不同的是,协议没有父类,并且不能定义成员变量。
下面的例子演示了只有一个方法的协议的声明:
@protocol MyProtocol
//@required/@optional
- (void)myProtocolMethod;
@end
协议中的方法声明的关键字:(主要是为了方便程序员之间的交流)
1.@required(默认):要求实现,如果没有实现,会有警告;
2.@optional:不要求实现,怎样都不会有警告。
协议是多个类共享的一个方法列表,协议中列出的方法没有相应的实现。如果一个类采用MyProtocol协议,则必须实现名为myProtocolMethod 的方法。
通过在@interface 行的一对尖括号<...>内列出协议名称,可以告知编译器你正在采用一个协议。这项协议的名称放在类名和它的父类名称之后,
如下所示:
@interface AddressBook: NSObject <myProtocol>
这说明, AddressBook 是父类为AddressBook 的对象,并且它遵守myProtocolMethod 协议。在AddressBook 的实现部分,编译器期望找到定义的myProtocolMethod 方法。
如果采用多项协议,只需把它们都列在尖括号中,用逗号分开:
@interface AddressBook: NSObject < myProtocol , yourProtocol >
以上代码告知编译器AddressBook 类采用myProtocolMethod 和yourProtocolMethod 协议。这次,编译器将期望在AddressBook 的实现部分看到为这些协议列出的所有方法的实现。
有关协议的注意事项:
A、如果一个类遵守某项协议,那么它的子类也遵守该协议。
B、协议不引用任何类,它是无类的(classless)。任何类都可以遵守某项协议。
C、限制对象类型:
通过在类型名称之后的尖括号中添加协议名称,可以借助编译器的帮助来检
查变量的一致性,如下:
id <Drawing> currentObject;
这告知编译器currentObject 将包含遵守Drawing 协议的对象。如果向 currentObject 指派静态类型的对象,这个对象不遵守Drawing 协议,编译器将给出warning。
再次提到id 类型,如果向currentObject 指派一个id 变量,不会产生这条消息,因为编译器不知道存储在id 变量中的对象是否遵守Drawing 协议。
D、如果这个变量保存的对象遵守多项协议,则可以列出多项协议,如下:
id <Drawing, Drawing 1> currentObject;
E、协议间的遵守:例如:
@protocol Drawing3D <Drawing>
说明Drawing3D 协议也采用了Drawing 协议。因此采用Drawing3D 协议的类都必须实现此协议列出的方法,以及Drawing 协议的方法。
基协议:任何协议都要遵守基协议。
基类遵守了基协议,所有类继承基类,也遵守基协议。
F、分类也可以采用一项协议,如:
@interface Fraction (stuff) <NSCopying, NSCoding>
此处,Fraction 拥有一个分类stuff,这个分类采用了NSCopying 和NSCoding 协议。
注:1.@property中声明的属性也可做一个遵守协议的限制:
@property (nonatomic,strong)类名<协议名> *属性名;
2. 协议可定义在单独的.h文件中,也可定义在类中:
(1)如果这个协议只用在某个类中,应该把协议定义在类中;
(2)如果这个协议用在很多个类中,应该把协议定义在单独.h文件中。
另外:分类可定义在单独的.h文件中,也可以定义在原来类中,一般都定义在.h文件中,定义在原来文件中的分类,只要求看懂代码。
四、练习
代理模型设计:
Person.h:
#import <Foundation/Foundation.h>
#import "TiketDelegate.h"
@interface Person : NSobject <TiketDelegate>
- (void)BuyTiket;
@property(nonatomic,retain) id<TiketDelegate> delegate;
@end
Person.m:
#import "Person.h"
@implementation Person
- (void)BuyTiket
{
double monkey = [_delegata tiketMonkey];
int number = [_delegate tiketNumber];
NSLog(@"找到一个代理,询问票价是:%f,剩余张数是:%d",monkey,number);
}
- (void)dealloc
{
[_delegate release];
[super dealloc];
}
@end
TiketDelegante.h:
#import <Foundation/Foundation.h>
@protocol TiketDelegate <NSobject>
@required
- (double)tiketMonkey;
- (int)tiketNumber;
@end
Agent.h:
#import <Foundation/Foundation.h>
#import "TiketDelegate.h"
@implementation Agent : NSobject <TiketDelegate>
@end
Agent.m:
#import "Agent.h"
@implementation Agent
- (double)TiketMonkey
{
return 100;
}
- (int)TiketNumber
{
return 10;
}
@end
main.m:
#import <Foudation/Foundation.h>
#import "Person.h"
#impiort "Agent.h"
int main()
{
@autoreleasepool{
Person *p = [[[Person alloc] init] autorelease];
Agent *a = [[[Agent alloc] init] autorelease];
p.delegate = a;
[p BuyTiket];
}
}