值传递:基本数据类型的变量之间的数据传递
//值传递不会改变变量的值
void func(int a)
{
a = 4;
}
int main(int argc, const char * argv[]) {
int a = 8 ;
func(a);
printf("%d",a);//答案为8
return 0;
}
```
## 指针类型之间的地址传递
```objc
//地址传递会改变变量的值
void func(int *a){
*a = 4;
}
int main(int argc, const char * argv[]) {
int a = 8 ;
func(&a);
printf("%d",a);//答案为4
return 0;
}
全局变量static和extern
1)static修饰的全局变量作用范围为定义变量的文件,变量存储在静态区,生命周期与程序生命一致;
2)extern只能声明变量,使作用范围扩大到整个程序文件,生命周期与程序生命一致;
代理设置模式的数据传值
代理模式是为了解决程序的低耦合,高内聚而产生,比如:
1)A对象做不了的事情,B对象来帮A做;
2)B对象想监听A对象的行为;
3)当A发生一些事情, 想通知B对象的时候
//A设计协议
@protocol testViewDelegate
@optional
-(void)outPut:(NSString *)theTitle;
@end
//B遵守协议...
//B实现协议方法...
通过系统通知传值
//先发布通知
/*
name:通知名称
object:谁发出通知
nil代表匿名发布 */
[[NSNotificationCenter defaultCenter] postNotificationName:@"note" object:nil];
//监听通知
//方式一:
/*
Observer:谁观察通知
selector:监听到通知,就会调用这个方法
name:通知名称
object:谁发出通知nil代表监听所有 */
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(reciveNote) name:@"note" object:nil];
//方式二:
/* name:通知名称
object:谁发出通知
queue: 确定Block在哪个线程调用 队列,传入nil,block就会直接运行在发布通知线程中
usingBlock:只要监听到通知,就会自动调用这个block */
_observer = [[NSNotificationCenter defaultCenter] addObserverForName:@"note" object:nil queue:nil usingBlock:^(NSNotification * _Nonnull note) {
NSLog(@"%@",self); NSLog(@"%@",[NSThread currentThread]);
NSLog(@"调用了block:监听到通知"); }];
//方式三
//userInfo表示传入的数据
[[NSNotificationCenter defaultCenter] postNotificationName:@"note" object:nil userInfo:nil];
通过的block传递(此项重点颇多)
- Block声明
// 声明:返回值(^block变量名)(参数)void(^block)();//(无返回值无参数)
- Block定义
// 定义
// 方式一:
void(^block1)() = ^(){NSLog(@"调用block1");};
// 调用Block,就会去查看下Block保存代码block1();
// 方式二:block如果没有参数,可以省略()
// void(^)()void(^block2)() = ^{};
// 方式三:block定义中,返回值可以省略
// 类型:int(^)()int(^block3)() = ^int{return 2;};
//在Xcode中的快捷键是inline
- Block类型
- 是对象
- Block作用
- 保存代码块
- Block:在一个类中定义,在另一个类中调用(常用), -> 传值
//在A类中定义一个block属性
@property (nonatomic ,strong) void(^block)();
//在B类中赋值
// 打电话
CellItem *item = [[CellItem alloc] init];
item.title = @"打电话";
item.block = ^{NSLog(@"打电话");};
//在B类方法中使用
if (item.block) {item.block();}
- 传值:A -> B 顺传:定义属性;B -> A 逆传:代理(block替换代理)
//为了替代代理
//在B类中声明block属性
@property (nonatomic ,strong) void(^valueBlock)(NSString *value);
//同时在B类中使用,把值传递出去
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
if (_valueBlock) {
_valueBlock(@"123");
}
}
//在A类中定义block(首先拿到B类就能拿到B类传出去的值)
ModalViewController *modalVc = [[ModalViewController alloc] init];
modalVc.valueBlock = ^(NSString *value){
NSLog(@"接收到%@",value);
};
block的变量传递
- 默认局部变量在block中 是值传递
- 如果局部变量被static,__block,那么都是指针传递
- 全局变量.也是指针传递
block作为参数使用
// 计算
- (void)calculate:(int(^)(int))block;
//实现方法(把值传递出去)
- (void)calculate:(int (^)(int))block{
_result = block(_result);
}
//在另一个类中定义
CalculateManager *mgr = [[CalculateManager alloc] init];
[mgr calculate:^(int result){
// 计算
result += 5;
result *= 2;
return result;
}];
block做为方法的返回值
//声明方法
- (CalculateManager *(^)(int))add;
//实现方法(此方法可以实现链式点语法)
- (CalculateManager *(^)(int))add{return ^(int value){
_result += value;
return self;
};
}
CalculateManager *mgr = [[CalculateManager alloc] init];
mgr.add(5).add(5).add(5).add(5);
block内存管理:
- 非ARC环境:block怎么去管理内存
- block没有访问外部局部变量,存放到全局区
- block访问外部局部变量,block存放栈里面
- 只要block访问变量,是整个app都在的变量,那么肯定在全局区
- 在非ARC中.不能使用retain引用block,不会把放在堆里面,在非ARC中只能使用copy,才会把block放在堆里面
- ARC环境:
- block访问外部局部变量,block存放堆里面
- 可以使用strong去引用
- 补充:内存五大区:堆,栈,方法区,全局区,常量区
- 堆:手动管理内存
- 栈:不需要手动管理内容,代码块一过,会自动清空栈里面内存
- 如何判断非ARC环境:
- 重写dealloc,调用super,ARC中不能调用[super dealloc]
- 判断下是否可以调用retain,release等等
- 非ARC开发中注意:
- 访问属性,不要直接使用_,而是通过set,get方法去访问
- 非ARC中没有weak -> assign,strong -> retain