1.类之间通信的原因
在Class中实例化BClass并调用BClass的方法之后,绝不能在BClass中再实例化AClass并调用AClass中的方法,会造成交叉引用,无法释放对象,这就是类之间通信的原因。
类之间通信的三大方式:Block 通知 委托代理
2.Block
//Block:代码块
//Block:1.声明 返回值+(MyBlock,也可以取名为其他的)声明+传递参数
typedef int (^MyBlock)(int);
//Block:2.实现
MyBlock b1 = ^(int b){
NSLog(@"我是一个代码块,我的接收参数是%d",b); //当调用b1的时候,就是在调用这个代码块
return b+1;
};
//Block:3.调用
int newB = b1(10);
NSLog(@"%d",newB);
输出结果:
我是一个代码块,我的接收参数是10
11
//Block:4.变量的作用范围
_block int a = 5;
MyBlock b1 = ^(int b){
NSLog(@"我是一个代码块,我的接收参数是a=%d b=%d",a,b);
a = a + 1;
return a+b;
};
a在Block外定义的,可以在Block里正常输出打印,但是不能在Block里对a进行操作,会报错,想解决的话定义a的时候在前面加_block。
代码的执行顺序:执行的时候执行到Block的时候会先跳过,直到调用它的时候才进入Block。
//Block:5.block在类之间通信的使用
//BClass.h
typedef void (^MyBlock)(NSString);
-(void)testBlock:(MyBlock)block str1:(NSString*)str1;
//BClass.m
-(void)testBlock:(MyBlock)block str1:(NSString*)str1{
NSLog(@"我是被谁调用的:%@",str1);
NSLog(@"我是一个B类");
block(@"我是从B类来的");
}
//AClass.h
#import "BClass.h"
//AClass.m
MyBlock b1 = ^(NSString *str1){
NSLog(@"AClass:%@",str1);
};
BClass *classb = [[BClass alloc]init];
[classb testBlock:b1 str1:@"AClass"];
运行结果:
我是被谁调用的:AClass
我是一个B类
AClass:我是从B类来的
//Block:6.快速的实现方法
BClass *classb = [[BClass alloc]init];
[classb testBlock:^(NSString* str1){
NSLog(@"AClass:%@",str1);
} str1:@"AClass"];
3.广播Notification
1.广播(通知)中心
2.发起人
3.接收者
4.步骤
①广播接收者向广播中心注册广播接收对象
②定义广播接收的方法
③发起人向广播中心发送广播
5.例:A发送,B接收
//main.m
#import "BClass.h"
BClass *b1 = [[BClass alloc]init];
[b1 testNotification];
//BClass.h
#import "AClass.h"
-(void)testNotification;
//BClass.m A->B
-(void)testNotification{
//①注册
//参数1:谁在接收这个方法 参数2:这个广播的响应方法 参数3:广播名称 参数4:别的广播发过来的时候是可以带一些自己的参数的
//self:当前的这个类
[[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(testAction) name:@"TESTNOTIF" object:nil];
Class *classa = [[AClass alloc]init];
/*带参数的广播
//加了个冒号
[[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(testAction:) name:@"TESTNOTIF" object:nil];
Class *classa = [[AClass alloc]init];
*/
}
-(void)testAction{
NSLog(@"我已经接收到广播");
}
/*带参数的广播
-(void)testAction:(NSNotification*)notify{
NSNumber *num = notify.object;
NSDictionary *dic = notify.userInfo;
NSLog(@"%@ %@",num,dic);
}
*/
//销毁
-(void)dealloc{
[[NSNotificationCenter defaultCenter]removeObserver:self name:@"TESTNOTIF" object:nil];
}
//AClass.m
-(id)init {
self = [super init];
if(self){
[[NSNotificationCenter defaultCenter]postNotificationName:@"TESTNOTIF" object:nil];
/*带参数的广播
NSMutableDictionary *dic = [[NSMutableDictionary alloc]init];
[dic setValue:@"123" forKey:@"keya"];
//参数1:广播的唯一标识符(名称) 参数2:object对象 参数3:一个字典
[[NSNotificationCenter defaultCenter]postNotificationName:@"TESTNOTIF" object:[NSNumber numberWithInt:5] userInfo:dic];
//NSNumber和Int都表示整型数据,唯一不同点是NSMumber是oc中的一个对象,而Int只是一个整型数据
*/
}
return self;
}
//一对多的广播
//Teacher.m
-(id)init {
self = [super init];
if (self) {
[[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(notification) name:@"TESTNOTIF" object:nil];
}
return self;
}
-(void)notification {
NSLog(@"Teacher已接收");
}
-(void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self name:@"TESTNOTIF" object:nil];
}
//Student.m
-(id)init {
self = [super init];
if (self) {
[[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(notification) name:@"TESTNOTIF" object:nil];
}
return self;
}
-(void)notification {
NSLog(@"Student已接收");
}
-(void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self name:@"TESTNOTIF" object:nil];
}
//Person.m
@interface Person() {
//类扩展
Student *s1;
Teacher *t1;
}
@end
@implementation Person
-(void)testNotification {
s1 = [[Student alloc]init];
t1 = [[Teacher alloc]init];
[[NSNotificationCenter defaultCenter]postNotificationName:@"TESTNOTIF" object:nil];
}
@end
//main.m
Person *p = [[Person alloc]init];
[p testNotification];
//多对一的广播
//Teacher.m
-(id)init {
self = [super init];
if (self) {
NSMutableDictionary *dic = [[NSMutableDictionary alloc]init];
[dic setValue:@"我来自Teacher" forKey:@"info"];
[[NSNotificationCenter defaultCenter]postNotificationName:@"TESTNOTIF" object:nil userInfo:dic];
}
return self;
}
//Student.m
-(id)init {
self = [super init];
if (self) {
NSMutableDictionary *dic = [[NSMutableDictionary alloc]init];
[dic setValue:@"我来自Student" forKey:@"info"];
[[NSNotificationCenter defaultCenter]postNotificationName:@"TESTNOTIF" object:nil userInfo:dic];
}
return self;
}
//Person.m
@interface Person() {
//类扩展
Student *s1;
Teacher *t1;
}
@end
@implementation Person
-(void)testNotification {
[[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(notification:) name:@"TESTNOTIF" object:nil];
s1 = [[Student alloc]init];
t1 = [[Teacher alloc]init];
}
-(void)notification:(NSNotification *)notification {
NSDictionary *d = notification.userInfo;
NSString *str = [d valueForKey:@"info"];
NSLog(@"%@",str);
}
-(void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self name:@"TESTNOTIF" object:nil];
}
@end
4.协议委托代理
1.定义协议(以找黄牛买票为例)
@property(nonatomic,weak) id
@protocol BuyTicketDelegate
@optional //表示下面的方法不一定要实现
-(void)buyTicket;
@end
2.委托
3.代理方法的调用
//Aclass.h
@protocol BuyTicketDelegate;
@interface AClass : NSObject
@property(nonatomic,weak) id
-(void)myBuyTicket;
@end
@protocol BuyTicketDelegate
@optional //表示下面的方法不一定要实现
-(void)buyTicket;
@end
//Aclass.m
-(void)myBuyTicket {
if ([self.Delegate respondsToSelector:@selector(buyTicket)]) {
[self.Delegate buyTicket];
}
//HuangNiu.h
#import "AClass.h"
@interface HuangNiu : NSObject
-(void)testDelegate;
@end
//HuangNiu.m
-(void)testDelegate {
AClass *classa = [[AClass alloc]init];
classa.Delegate = self;//委托
[classa myBuyTicket];
}
-(void)buyTicket {
NSLog(@"我是黄牛,我正在帮你买票");
}
5.定时器
1.定时器的基本使用
2.定时器的精度
3.代码的执行时间
//main.m
#import
#import "MyTimer.h"
int main(int argc, const char * argv[]) {
@autoreleasepool {
MyTimer *timer = [[MyTimer alloc]init];
[timer testTimer];
}
return 0;
}
//MyTimer.h
#import
@interface MyTimer : NSObject
-(void)testTimer;
@end
//MyTimer.m
#import "MyTimer.h"
@interface MyTimer() {
NSTimer *timer1;
NSTimer *timer2;
}
@end
@implementation MyTimer
-(void)testTimer {
//1. 参数一:中断间隔,单位是s 参数二:当前定时器的响应方法是哪个对象来响应 参数三:响应方法 参数四:需要传递的参数 参数五:是否重复
// timer1 = [NSTimer timerWithTimeInterval:1 target:self selector:@selector(myLog) userInfo:nil repeats:false];
// [[NSRunLoop currentRunLoop]addTimer:timer1 forMode:NSDefaultRunLoopMode];
// [[NSRunLoop currentRunLoop]run];
//2. 带参数定时器 + 非RunLoop方法
// timer2 = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(myLog:) userInfo:@"hello" repeats:false];//这个方法直接将定时器放入RunLoop当中
// [timer2 fire];
// 3. 定时精度 0.01s = 10ms 只能粗略的计算,并不是准确的10ms
// timer1 = [NSTimer timerWithTimeInterval:0.01 target:self selector:@selector(myLog) userInfo:nil repeats:true];
// [[NSRunLoop currentRunLoop]addTimer:timer1 forMode:NSDefaultRunLoopMode];
// [[NSRunLoop currentRunLoop]run];
//4. 如何快速的打印出当前代码执行时间
NSDate *timeMark = [NSDate date];
NSLog(@"hello");
NSLog(@"hello");
NSLog(@"hello");
NSTimeInterval timeInterval = [timeMark timeIntervalSinceNow];//上面三个打印hello的时间差,是个负数
float timeNow = 0 - timeInterval;
NSLog(@"timeNow = %f",timeNow);
}
-(void)myLog {
NSLog(@"我是一个定时器");
}
-(void)myLog:(NSTimer *)timer {
NSLog(@"我是定时器2 = %@",timer2.userInfo);
}
@end
6.KVC(Key Value Coding)和KVO(键值观察)
1.kvc的基本使用
动态设置:
setValue:属性值 forKey:属性名
setValue:属性值 forKeyPath:属性路径
动态读取:
valueForKey:属性名
valueForKeyPath:属性路径
在一般修改一个对象的属性的时候,forKey和forKeyPath,没什么区别。如:
[Person setValue:@"lisiv" forKey:@"name"];
[Person setValue:@"jack" forKeyPath:@"name"];
这两种都可以。
如果看层次结构深一点的。比如person还有其他属性,dog,car等等
就只能通过forKeyPath,它能使用点语法,深层次的去寻找我们需要的属性。如:
[Person setValue:@"kala" forKeyPath:@"Person.dog.name"];
2.kvo的基本使用
监听对象属性的变化
步骤:①注册 ②观察 ③移除观察
//KVOClass.h
#import
#import "Person.h"
@interface KVOClass : NSObject
@property(nonatomic,strong)Person *p1;
-(void)testKVO;
@end
//KVOClass.m
#import "KVOClass.h"
@implementation KVOClass
-(void)testKVO {
//1.注册
self.p1 = [[Person alloc]init];
[self.p1 setAge:15];
[self.p1 addObserver:self forKeyPath:@"age" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:nil];
[self.p1 setAge:18];
}
//3.移除-(void)dealloc {
[self.p1 removeObserver:self forKeyPath:@"age"];
}
//2.观察
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
NSLog(@"我的年龄变化了");
}
@end
3.KVO监听股票价格(计时器模拟价格变动)
//Stock.h
@property(nonatomic,assign) float price;
//KVOClass.h
#import
#import "Stock.h"
@interface KVOClass : NSObject
@property(nonatomic,strong)Stock *p1;
@property(nonatomic,strong)NSTimer *timer;
-(void)testKVO;
@end
//KVOClass.h
#import "KVOClass.h"
float currentPrice;
@implementation KVOClass
-(void)testKVO {
//1.注册
self.p1 = [[Stock alloc]init];
currentPrice = 3.6;
[self.p1 setPrice:currentPrice];
[self.p1 addObserver:self forKeyPath:@"price" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:nil];
self.timer = [NSTimer timerWithTimeInterval:1 target:self selector:@selector(priceChange) userInfo:nil repeats:true];
[[NSRunLoop currentRunLoop]addTimer:self.timer forMode:NSDefaultRunLoopMode];
[[NSRunLoop currentRunLoop]run];
}
-(void)priceChange {
currentPrice += 0.1;
[self.p1 setPrice:currentPrice];
}
//3.移除
-(void)dealloc {
[self.p1 removeObserver:self forKeyPath:@"price"];
}
//2.观察
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
NSString *oldPriceString = [change valueForKey:@"old"];//old和new是约定俗成的
NSString *newPriceString = [change valueForKey:@"new"];
float oldPrice = oldPriceString.floatValue;
float newPrice = newPriceString.floatValue;
if (newPrice > oldPrice) {
NSLog(@"当前股价正在上涨,当前股价为%0.2f",newPrice);
}
}
@end