转自:http://kan.weibo.com/con/3516583830745467
/**
用来内存管理第一部分的测试函数
@param value1 第一个整型值
@param num2 第二个参数
*/
int _testBlock(constint value1,int num2);
int _testBlock(constint value1,int num2)
{
return value1 + num2;
}
int main(int argc, constchar * argv[])
{
//Block 数据类型
//1、声明Block 数据类型变量
int num1 = 7;
/**
Block 数据类型与结构体类型相似指的都是泛指类型的数据类型,即需要声明具有实际意义的Block数据类型或结构体类型
int(^aBlock)(int num2),第一个int指的是当前Block数据类型的返回值的类型是整型,可以换成其他数据类型,^aBlock在小括号内表示的数据类型为aBlock,第二个int num2即为参数
^(int num2){
return num1+num2;
}; 赋值运算符的后边,即为Block变量的值,大括号内是函数实现的逻辑,即可以随意更改为其他逻辑,例如return num1 * num2等等;
*/
int(^aBlock)(int num2) = ^(int num2){
return num1+num2;
};
//同样可以通过类型定义,定义具体的Block数据类型,下面即定义一个返回值为整型,只有一个整型参数的myBlock数据类型
typedefint(^myBlock)(int num2);
//可以通过myBlock数据类型声明变量
myBlock bBlock = ^(int num2){
return num1 - num2;
};
//使用第一种方式定义的Block变量
NSLog(@"aBlock = %d",aBlock(3));
//使用第二种方式定义的Block变量
NSLog(@"bBlock = %d",bBlock(3));
//2、Block 变量涉及到的内存问题
int value1 = 2;
//定义具体的Block数据类型CaculateBlock
typedefint(^CaculateBlock)(int num2);
CaculateBlock _block = ^(int num2){
//value1++是不可以改变的
//在Block变量的内部,使用外部的变量时是只读的
return value1 + num2;
};
/**
重新修改valu1的值,结果等于4 而不是5
我们可以通过另外一种方式理解,再main函数外定义一个函数 int _testBlock(const int value1,int num2);
*/
//想想为什么_testBlock一定要在上边调用?
NSLog(@"_testBlock = %d",_testBlock(value1,2));
value1 = 3;
NSLog(@"_block = %d",_block(2));
//怎么解决这种问题只读变量的问题呢,使用__block关键字
__blockint value2 = 2;
CaculateBlock _block2 = ^(int num2){
value2 ++;
return value2 - num2;
};
value2++;
//4-3 = 1,value2是怎么变成4的呢,很明显是value2的两次自增变化的
NSLog(@"_block2 = %d",_block2(3));
//总结内存问题,就是几句话,每一个Block变量是存储在一个栈区stack1(因为是局部变量的原因),但是因为每一个Block变量的值是一段代码块,所以Block变量的值自己也负责管理一片栈区stack2的内存,当Block变量出栈后,Block变量的值自己负责的栈也会自动出栈。
//那么声明Block数据类型的变量的过程中,使用外部变量的时候,使用__block关键字的话,该外部变量可以理解为一个小型的全局变量,但是全局仅限于Block变量中使用,否则不使用__block关键字的话,在声明Block数据类型时,是将该外部变量的值赋值到Block变量自己负责的栈区内,并设置为const只读变量,所以及时修改了外部变量的值,仍然不会影响到Block自己负责的栈区的只读变量的值,因为它们已经是两片内存区域了。
//3、由于使用Block引起的retain cycle即循环持有的问题.
//举例,封转一个学生类FOStudent
/**
//定义一个具体的Block数据类型
typedef int(^StudentBlock) (int _age);
@interface FOStudent : NSObject
//实例属性要写copy,使用copy关键字的作用就是将任意一片内存区域的内容,赋值相同的一份到堆内存
@property (nonatomic ,copy) StudentBlock block;
//年龄,一个测试属性
@property (nonatomic ,assign) int age;
@end
@implementation FOStudent
@synthesize block;
@synthesize age;
- (void)dealloc
{
//在delloc中,在控制台打印delloc消息,提示我们该实例对象已被销毁
NSLog(@"%s",__FUNCTION__);
self.block = nil;
self.age = 0;
[super dealloc];
}
@end
*/
//实例化学生对象
FOStudent *student = [[FOStudentalloc] init];
StudentBlock _studentBlock = ^(int _age){
return student.age + _age;
};
//设置student的block实例属性为刚刚声明的_studentBlock局部变量,因为实例属性使用的是copy关键字,所以局部变量_studentBlock会赋值到堆内存中,并且生命周期与student实例对象相同(因为是在dealloc中释放的实例对象block内存),
student.block = _studentBlock;
//当对student实例对象发送release消息后,发现并没有delloc内容在控制台输出
[student release],student = nil;
//说明student实例对象并没有销毁内存,到底是在哪里它的引用计数器又加1了呢,根据第二部分的理解,声明Block变量的过程中,如果使用到的外部变量没有使用__block关键字,是会拷贝一份到Block变量自己负责的栈区,同理,在OC对象作为外部变量使用到Block变量中的时候,会对该对象的引用计数器+1,并且是在出栈的时候引用计数器-1,因为该block变量已经作为student实例对象的属性与student的声明周期相同,结果student对象不销毁,block不销毁,block不销毁,也就不会出栈,结果造成了retain cycle问题.
//怎么解决问题呢?
//仍然是使用__block关键字,因为__block关键字会定义小型的全局变量
FOStudent *_student = [[FOStudentalloc] init];
__blockFOStudent *bStudent = _student;
StudentBlock _bstudentBlock = ^(int _age){
return bStudent.age + _age;
};
_student.block = _bstudentBlock;
//这样通过这种方式的输出,_student对象就可以销毁了,并且也在控制台进行了输出
[_student release],_student = nil;
return0;
}
分享到:
相关推荐
1. **基础语法**:学习Objective-C首先需要了解它的基本语法,包括变量定义、数据类型、运算符、流程控制语句等。此外,还会涉及Objective-C中的特殊语法,如nil和NULL的区别、实例变量和属性的使用。 2. **类与...
3. **Foundation框架**:Objective-C的基础库,提供了许多基本的数据类型和常用功能。例如,NSArray、NSDictionary、NSString等重要类的使用可能会被深入讨论。 4. **内存管理**:Objective-C使用引用计数...
Objective-C的数据类型大部分沿用了C语言中的数据类型,如整型(`int`, `long`, `short`)、浮点型(`float`, `double`)等。此外,还有一些特殊的类型,如`NSString`、`NSArray`等用于处理字符串和数组等对象。 - ...
2. **基本语法**:讲解Objective-C的基础语法,如变量声明、常量定义、数据类型、流程控制(条件语句和循环)等。 3. **Objective-C的对象和类**:深入讨论面向对象编程的核心概念,如类的定义、实例化、继承、多态...
8. **Foundation框架与AppKit/UIKit**:Objective-C开发中常用的Foundation框架提供了基本的数据类型和系统服务,而AppKit(macOS)和UIKit(iOS)则提供了图形用户界面的组件和功能。 9. **Cocoa与Cocoa Touch**:...
在学习Objective-C时,你需要了解C语言的基本概念,如变量、数据类型、控制结构等。同时,Objective-C引入了消息传递机制,这是其面向对象特性的核心。相比于C,Objective-C更注重对象间的通信,通过发送消息来调用...
Objective-C是C语言的超集,这意味着你可以编写任何有效的C语言代码,同时还能利用Objective-C提供的面向对象特性。它的核心概念包括类、对象、消息传递和协议。类是对象的蓝图,定义了对象的属性和行为;对象则是类...
- **变量与数据类型**:介绍Objective-C中的基本数据类型,包括整型、浮点型等;讲解变量的声明和初始化方法。 - **控制结构**:学习条件语句(如if-else)、循环语句(如for、while)及跳转语句(如break、...
7. **Foundation框架**:Objective-C的基础库,提供基本的数据类型、集合类(如NSArray、NSDictionary)、线程管理等功能。 8. **UIKit框架**:iOS开发中用于构建用户界面的主要框架,包括UI控件、事件处理等。 9....
书中深入讲解了Objective-C的语法结构,包括变量、数据类型、控制结构、函数、指针等基础知识。此外,还重点阐述了Objective-C特有的特性,如动态消息传递、协议、属性、块(block)等,这些特性是理解和掌握...
其次,书中的内容涵盖Foundation框架,这是Objective-C开发中的基础库,包含了诸如字符串、数组、字典等基本数据类型以及文件操作、网络通信等功能。读者将学习如何使用这些工具进行实际编程。 再者,本书还会介绍...
在Objective-C中,数据类型、书写规范和格式符都是基础知识。学习者需要掌握不同数据类型(如基本数据类型、指针类型等)以及如何在代码中正确使用它们。书写规范涉及代码的排版和风格,有助于维护和理解代码。格式...
Objective-C的语法基于C语言,这意味着学习Objective-C首先要熟悉C语言的基本语法,包括变量、数据类型、控制结构等。Objective-C增加了消息传递机制,这是其面向对象特性的核心。通过发送消息给对象,可以调用对象...
Foundation框架提供了基础的数据类型、集合类和网络支持,而UIKit框架则包含了用于构建用户界面的所有元素。 10. **Xcode集成开发环境** Xcode是Apple官方的开发工具,包含了编写、调试和打包Objective-C应用所需...
3. **Foundation框架**:Objective-C的重要库之一是Foundation框架,它提供了大量基础数据类型、集合类以及系统服务。书中会介绍NSArray、NSDictionary、NSString等常用类的使用方法。 4. **Cocoa和Cocoa Touch**:...
7. **Foundation框架**:这是Objective-C的基础库,提供了许多常用的数据类型和操作,如字符串、集合、文件系统操作等。 8. **Core Foundation**和**Cocoa Touch**:Core Foundation是C语言的底层框架,而Cocoa ...
1. **理解Objective-C的基础概念**:这部分内容旨在帮助读者熟悉Objective-C的基本语法结构,包括变量定义、数据类型、运算符等基础知识。 2. **面向对象编程(OOP)的核心原则**:书中详细介绍了继承、封装、多态性等...