转载

OC基础--ARC Category Block

autorelease

什么是自动释放池?

autorelease是一种支持引用计数的内存管理方式,只要给对象发送一条autorelease消息,会将对象放到一个自动释放池中,当自动释放池被销毁时,会对池子里面的所有对象做一次release操作

自动释放池的优点是什么?

1.不用再担心对象释放的时间

2.不用再关心什么时候添加release

自动释放池的原理?

autorelease实际上只是把对release的调用延迟了,对于每一个autorelease,系统只是把该对象放入了当前的autorelease pool中,当该pool被释放时,该pool中的所有对象会被调用release。

如何使用自动释放池?

第一种:

NSAutoreleasePool *autoreleasePool = [[NSAutoreleasePool alloc] init]; Person *p = [[[Person alloc] init] autorelease]; [autoreleasePool release];

第二种:

@autoreleasepool {     // 创建一个自动释放池     Person *p = [[[Person alloc]init] autorelease]; } // 销毁自动释放池(会给池子中所有对象发送一条release消息)

自动释放池的注意:

  1. 在自动释放池中创建了对象, 一定要调用autorelease,才会将对象放入自动释放池中一个程序中可以创建N个自动释放池, 并且自动释放池还可以嵌套不要再自动释放池中使用比较消耗内存的对象, 占用内存比较大的对象尽量不要再自动释放池中使用循环, 特别是循环的次数非常多, 并且还非常占用内存千万不要写多次autorelease一个alloc/new对应一个autorelease或者release

自动释放池的存储

如果存在多个自动释放池时候,自动释放池是以 "栈" 的形式存储在堆中,而 "栈" 的特点就是 "先进后出"

ARC

什么是ARC

Automatic(自动)  Reference(引用)  Counting(计数器)

ARC的原理

当ARC开启时,编译器将自动在代码合适的地方插入retain, release和autorelease,而作为程序猿,完全不需要担心编译器会做错(除非开发者自己错用ARC了)。

ARC的优点

  1. 完全消除了手动管理内存的烦琐, 让程序猿更加专注于app的业务基本上能够避免内存泄露有时还能更加快速,因为编译器还可以执行某些优化

ARC的原则是什么?什么是强指针?什么是弱指针?

只要还有一个强指针指向对象,那么这个对象就会一直保持在内存中,不会被释放(除非程序退出)

强指针: 被 _strong 修饰的指针变量就是强指针

默认所有的指针变量都是强指针

Person *p1 = [[Person alloc] init]; __strong  Person *p2 = [[Person alloc] init];

弱指针: 被 _weak 修饰的指针变量就是弱指针

__strong  Person *p = [[Person alloc] init];

ARC中怎么对对象进行内存管理

首先我们需要了解ARC下@property修饰符有哪些?

  • strong : 用于OC对象, 相当于MRC中的retain
  • weak : 用于OC对象, 相当于MRC中的assign
  • assign : 用于基本数据类型, 跟MRC中的assign一样

对单个对象管理

1.ARC下,所有的指针都是强指针

2.ARC下,A对象想用有B对象,那么就需要用一个强指针指向B对象

3.当A对象不想用B对象了,什么都不需要做,系统会自动帮我们做

ARC下多对象内存管理(strong ,weak, assign)

// 在ARC中保存一个对象用strong, 相当于MRC中的retain @property(nonatomic, strong)Dog *dog; // 在ARC中如果保存对象不要用assign, 用weak // assign是专门用于保存基本数据类型的, 如果保存对象用weak @property(nonatomic, weak)Person *owner;

ARC下怎么解决循环引用问题?

ARC和MRC一样, 如果A拥有B, B也拥有A, 那么必须一方使用弱指针 也就是说 一端用strong ,一端用weak

ARC下如何兼容非ARC

找到project->targets->Bulid Phases->Compiles Sources->找到相关文件右击右边Compiler Flags添加相关代码

转非ARC: -fno-objc-arc

转ARC: -f-objc-arc (不常用,想在的Xcode默认就是ARC)

OC基础--ARC Category Block

如何通过Xcode将MRC转为ARC

Edit->Convert->To Objective ARC

OC基础--ARC Category Block

Category

Category是什么

Category是OC特有的语法,Category有很多种翻译: 分类 / 类别 / 类目 (一般叫分类)

作用:

1.在不改变原来类的基础上为这个类拓展一些方法

2.一个庞大的类可以分模块开发,多人开发,更有利于团队开发

分类的格式

// 分类的声明 @interface ClassName (CategoryName) NewMethod; //在类别中添加方法 //不允许在类别中添加变量 @end ClassName: 需要给哪个类扩充方法 CategoryName: 分类的名称 NewMethod: 扩充的方法 // 分类的实现 @implementation ClassName(CategoryName) NewMethod ... ... @end ClassName: 需要给哪个类扩充方法 CategoryName: 分类的名称 NewMethod: 扩充的方法

Xcode创建分类

OC基础--ARC Category Block

OC基础--ARC Category Block

分类的注意

1.分类用于给原有类添加方法,只能添加方法,不能添加成员变量

2.分类中的@property, 只会生成setter/getter方法的声明, 不会生成成setter/getter方法的实现以及私有的成员变量

3.可以在分类中访问原有类 .h 中的成员

4.如果分类中有和原有类同名的方法,会调用分类中的,也就是说会忽略原有类的方法

分类,原来类或者父类中的方法调用的顺序?

分类(最后参与编译的优先) --> 原有类 -->父类

匿名分类--类扩展--延展

什么是类扩展

延展类别又称为扩展(Extension),Extension是Category的一个特例

类扩展的书写格式

@interface 类名 () @end

类扩展的作用

写在.m文件中,可以为某个类扩充一些私有的成员变量和方法

Block

什么是block

Block是iOS中一种比较特殊的数据类型,用来保存某一段代码

block的作用

Block用来保存某一段代码, 可以在恰当的时间再取出来调用 功能类似于函数和方法

Block的格式:

返回值类型 (^block变量名)(形参列表) = ^(形参列表) { };

1.无参无返回值

// void代表block将来保存的代码没有返回值 // ()代表block将来保存的代码没有形参 // (^roseBlock) 代表reseBlock是一个block变量, 可以用于保存一段block代码 void (^roseBlock) (); // 如果block没有参数, 那么^后面的()可以省略 roseBlock = ^(){  printf("  {@} /n");  printf("   |  /n");  printf("  //|/ /n");  printf("   | /n"); }; // 要想执行block保存的代码, 必须调用block才会执行 roseBlock(); roseBlock(); 

2.有参无返回值

void (^roseBlock) (int); roseBlock = ^(int num){  for (int i = 0; i < num; ++i) {   printf("  {@} /n");   printf("   |  /n");   printf("  //|/ /n");   printf("   | /n");  } }; roseBlock(2); 

3.有参有返回值

int (^sumBlock) (int, int); sumBlock =^(int value1, int value2){     return value1 + value2; }; NSLog(@"sum = %i", sumBlock(10, 40));

怎么使用typedef给block起别名

首先回顾下给指向函数起别名

typedef int (*calculte)(int, int); int (*sumP)(int, int); //    sumP = sum; calculte sumP = sum; NSLog(@"sum = %i", sumP(20, 10)); //    int (*minusP)(int, int); //    minusP = minus; calculte minusP = minus; NSLog(@"minus = %i", minusP(20, 10));

给block起别名

// 注意: 利用typedef给block起别名, 和指向函数的指针一样, block变量的名称就是别名 typedef int (^calculteBlock)(int , int); calculteBlock sumBlock = ^(int value1, int value2){  return value1 + value2; }; NSLog(@"sum = %i", sumBlock(20, 10)); // int (^minusBlock)(int , int); calculteBlock minusBlock = ^(int value1, int value2){  return value1 - value2; }; NSLog(@"minus = %i", minusBlock(20, 10)); 

block的应用场景

当发现一段代码前后一样,中间不一样时,这个时候可以用block

Block使用注意

1,怎么访问和修改外部变量

int a = 10; void (^myBlock)() = ^{     NSLog(@"a = %i", a); }; myBlock();

修改

__block int a = 10; void (^myBlock)() = ^{     a = 20     NSLog(@"a = %i", a); }; myBlock();

2.为什么不可以在block中修改外部变量的值

  1. 默认情况下, 不可以在block中修改外界变量的值,因为block中使用的外界变量是copy的, 所以在调用之前修改外界变量的值, 不会影响到block中copy的值
  2. 因为block中的变量和外界的变量并不是同一个变量
  3. 如果block中访问到了外界的变量, block会将外界的变量拷贝一份到堆内存中
int a = 10; NSLog(@"&a = %p", &a); void (^myBlock)() = ^{  //  a = 50;  NSLog(@"&a = %p", &a);  NSLog(@"a = %i", a); }; a = 20; myBlock(); 

3.__block的应用场景

如果想在block中修改外部变量的值,那么必须在外部变量前面加上 __block

__block int a = 10; NSLog(@"&a = %p", &a); void (^myBlock)() = ^{  a = 50;  NSLog(@"&a = %p", &a);  NSLog(@"a = %i", a); }; myBlock(); NSLog(@"a = %i", a); 

4.为什么要加上 __block 才能再block中修改外部变量的值

因为加上 __block 后就是地址传递

5.block的存储位置

  1. 默认情况下block存储在栈中, 如果对block进行一个copy操作, block会转移到堆中如果block在栈中, block中访问了外界的对象, 那么不会对对象进行retain操作但是如果block在堆中, block中访问了外界的对象, 那么会对外界的对象进行一次retain

6.怎么对block进行内存管理

  1. 如果在block中访问了外界的对象, 一定要给对象前面加上__block, 只要加上了__block, 哪怕block在堆中, 也不会对外界的对象进行retain
  2. 如果是在ARC开发中就需要在前面加上__weak
__block Person *p = [[Person alloc] init]; // 1

7.如何防止block循环引用

1.使用一个用__weak 修饰的值指针保存对象

2.或者使用Block_copy(myBlock)

ARC

//Person *p = [[Person alloc] init]; // __weak Person *weakP = p; NSLog(@"retainCount = %lu", [p retainCount]); void (^myBlock)() = ^{  NSLog(@"p = %@", p); // 2  //  NSLog(@"p = %p", weakP);  NSLog(@"block retainCount = %lu", [p retainCount]); }; Block_copy(myBlock);//将block对象转移到堆中 myBlock(); [p release]; 1 

MRC

__block Person *p = [[Person alloc] init]; // 1
正文到此结束
Loading...