不务正业之OC(七)–KVO介绍–观察者模式

KVO类似数据库中的trigger,就是当属性值发生变化时,能够通知到目标对象(注册者)
定义两个类,Baby.h和Mother.h,当Baby对象对属性wawa发生变化时,Mother对象就能知道

//  Baby.h
#import <Foundation/Foundation.h>
 
@interface Baby : NSObject
@property (nonatomic,assign) NSInteger  wawa;
@end
 
//  Baby.m
#import "Baby.h"
 
@implementation Baby
- (id)init{
    if(self = [super init]){
        self.wawa = 20;
         //定义定时器,每1s触发调用timerAction,wawa实例变量减1
        [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(timerAction:) userInfo:nil repeats:YES];
    }
    return self;
}
 
- (void) timerAction:(NSTimer *)timer{
    self.wawa--;
}
@end
//  Mother.h
 
#import <Foundation/Foundation.h>
#import "Baby.h"
 
@interface Mother : NSObject
 
@property(nonatomic,retain) Baby *baby;
 
- (id) initWithBaby:(Baby *)baby;
 
@end
 
//  Mother.m
 
#import "Mother.h"
 
@implementation Mother
 
- (id) initWithBaby:(Baby *)baby{
    if(self = [super init]){
        self.baby = baby;
        //对baby增加一观察者mother,当wawa发生变化时调用observeValueForKeyPath方法
        [self.baby addObserver:self forKeyPath:@"wawa" options:NSKeyValueObservingOptionNew context:nil];
    }
    return self;
}
 
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context{
    NSLog(@"wawa %@",change);
}
 
@end

main.m实现

//  main.m
 
#import <Foundation/Foundation.h>
#import "Mother.h"
 
int main(int argc, const char * argv[])
{
 
    @autoreleasepool {
        Baby *myBaby = [[Baby alloc] init];
        Mother *myMother =[[Mother alloc] initWithBaby:myBaby];
        [[NSRunLoop currentRunLoop] run];
    }
    return 0;
}

执行流程:
1、调用定时器,Baby对象的定时器启动[NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(timerAction:) userInfo:nil repeats:YES],触发wawa减1
2、观察者[self.baby addObserver:self forKeyPath:@”wawa” options:NSKeyValueObservingOptionNew context:nil]发现wawa发生变化,调用observeValueForKeyPath

结果:

2014-04-30 20:08:06.646 KVO[13671:303] wawa {
    kind = 1;
    new = 19;
}
2014-04-30 20:08:07.641 KVO[13671:303] wawa {
    kind = 1;
    new = 18;
}
2014-04-30 20:08:08.642 KVO[13671:303] wawa {
    kind = 1;
    new = 17;
}

不务正业之OC(六)–KVC介绍

KVC可以在不定义对象属性访问器、定义成private时,也可以直接访问。
缺点:KVC错误发现,一般在运行期

定义两个类Person.h、House.h,这个看头文件就行,不需要实现

//  Person.h
 
#import <Foundation/Foundation.h>
 
@interface Person : NSObject
{
    @private
    NSString *_name;
    float _salary;
}
 
@end
 
//  House.h
 
#import <Foundation/Foundation.h>
#import "Person.h"
 
@interface House : NSObject
{
@private
    Person *_person;
    NSMutableArray *_famliy;
    NSMutableArray *_money;
}
 
@end

main.m

//  main.m
 
#import <Foundation/Foundation.h>
#import "House.h"
//#import "Person.h"  在House.h已导入
int main(int argc, const char * argv[])
{
 
    @autoreleasepool {
        Person *person = [[Person alloc] init];
        //KV访问
        [person setValue:@"lijie" forKey:@"_name"];
        NSString *name1 = [person valueForKey:@"_name"];
        NSLog(@"name1 is: %@",name1);
        NSString *name2 = [person valueForKey:@"name"];
        NSLog(@"name2 is: %@",name2);
 
        //路径访问
        House *house = [[House alloc] init];
        [house setValue:person forKeyPath:@"_person"];
        [house setValue:@"liyi" forKeyPath:@"_person._name"];
        NSString *myson = [house valueForKeyPath:@"_person._name"];
        NSLog(@"house owner is: %@",myson);
 
        //一对多
        NSMutableArray *famliy = [NSMutableArray arrayWithCapacity:30];
        Person *person1 = [[Person alloc] init];
        NSString *name_a = [NSString stringWithFormat:@"monther"];
        [person1 setValue:name_a forKey:@"_name"];
        Person *person2 = [[Person alloc] init];
        NSString *name_b = [NSString stringWithFormat:@"grandma"];
        [person2 setValue:name_b forKey:@"_name"];
        [famliy addObject:person1];
        [famliy addObject:person2];
 
        [house setValue:famliy forKey:@"_famliy"];
        NSArray *whos1 = [house valueForKeyPath:@"_famliy._name"];
        NSLog(@"%@",whos1);
 
        NSArray *whos2 = [famliy valueForKey:@"_name"];
        NSLog(@"%@",whos2);
 
        //简单运算 sum、min、max、avg、count
        [person1 setValue:[NSNumber numberWithFloat:2.1] forKey:@"_salary"];
        [person2 setValue:[NSNumber numberWithFloat:7.1] forKey:@"_salary"];
        NSMutableArray *money = [NSMutableArray arrayWithCapacity:3];
        [money addObject:person1];
        [money addObject:person2];
        [house setValue:money forKey:@"_money"];
 
 
        NSNumber *sum = [house valueForKeyPath:@"_money.@sum._salary"];
        NSLog(@"sum is %@",sum);
 
        NSNumber *min = [house valueForKeyPath:@"_money.@min._salary"];
        NSLog(@"min is %@",min);
 
        NSNumber *max = [house valueForKeyPath:@"_money.@max._salary"];
        NSLog(@"max is %@",max);
 
        NSNumber *avg = [house valueForKeyPath:@"_money.@avg._salary"];
        NSLog(@"avg is %@",avg);
 
        NSNumber *count = [house valueForKeyPath:@"_money.@count"];
        NSLog(@"count is %@",count);   
    }
    return 0;
}
KVC[13423:303] name1 is: lijie
KVC[13423:303] name2 is: lijie
KVC[13423:303] house owner is: liyi
KVC[13423:303] (
    monther,
    grandma
)
KVC[13423:303] (
    monther,
    grandma
)
KVC[13423:303] sum is 9.2
KVC[13423:303] min is 2.1
KVC[13423:303] max is 7.1
KVC[13423:303] avg is 4.6
KVC[13423:303] count is 2

不务正业之OC(五)-dealloc方法介绍

deallloc方法调用时机:当对象引用计数为0时,销毁对象
首先我们来创建三个类:Compute、Liptop、Cpu。Liptop为Compute的子类。

Compute类定义及实现

//  Compute.h
 
#import <Foundation/Foundation.h>
 
@interface Compute : NSObject{
    NSString * _name; //设置Compute名字
}
- (id) initWithName:(NSString *) name;
 
@end
 
//  Compute.m
 
#import "Compute.h"
 
@implementation Compute
 
- (id) initWithName:(NSString *) name{
    if (self = [super init]) {
        _name = [name retain];
    }
    return self;
}
 
- (void) dealloc{ //重写dealloc方法
    NSLog(@"Compute is broken!");
    [_name release];
    [super dealloc];
}
@end

Liptop定义及实现

//  Liptop.h
 
#import "Compute.h"
 
@class Cpu;
 
@interface Liptop : Compute
{
    Cpu *_cpu;
}
@property (retain) Cpu *_cpu;//实现Liptop的cpu型号
 
@end
 
//  Liptop.m
 
#import "Liptop.h"
 
@implementation Liptop
 
@synthesize _cpu;
 
- (void) dealloc{
    NSLog(@"Liptop is broken!");
    [_cpu release];
    [super dealloc];
}
@end

Cpu定义及实现

//  Cpu.h
 
#import "Liptop.h"
 
@interface Cpu : NSObject
 
@end
 
//  Cpu.m
 
#import "Cpu.h"
 
@implementation Cpu
- (void) dealloc{
    NSLog(@"Cpu is broken!");
    [super dealloc];
}
 
@end

main函数实现

//  main.m
#import <Foundation/Foundation.h>
#import "Compute.h"
#import "Liptop.h"
#import "Cpu.h"
 
int main(int argc, const char * argv[])
{
 
    @autoreleasepool {
        //定义新对象liptop_name做为liptop的名字
        NSString *liptop_name = [[NSString alloc] initWithFormat:@"My liptop"];
        Liptop *liptop = [[Liptop alloc] initWithName:liptop_name];
        //释放liptop_name,因为liptop_name所有权给Copmute对象的_name,_name = [name retain],记得一定retain(copy\new也行),不然访问就挂了
        [liptop_name release];
        //设置liptop对象的cpu为intel
        Cpu *intel = [[Cpu alloc] init];
        liptop._cpu = intel;
        //释放intel,对象所有权给_cpu,记得@property (retain) Cpu *_cpu,一定要retain(copy\new也行),不然访问就挂了
        [intel release];
        //释放liptop,调用liptop的dealloc方法,需要把自己的拥有的对象释放掉_cpu,同时调用父类的dealloc方法,来销毁_name对象
        [liptop release];
    }
    return 0;
}

运行结果:
Dealloc[12118:303] Liptop is broken!
Dealloc[12118:303] Cpu is broken!
Dealloc[12118:303] Compute is broken!

不务正业之OC(四)–memory leak修复

方法1:只需要修改Bike.m、main.m,setTire方式时,使用retain,使用引用计数加1,_tire获得对象所有权,_tire要负责释放tire对象,所以当释放Bike时,dealloc方法中调用[_tire release];main.m增加[b release];

#import "Bike.h"
@implementation Bike
- (void) setTire:(Tire *) tire{
    _tire = [tire retain]; //转交所有权
}
 
- (Tire *) Tire{
    return _tire;
}
 
- (void) dealloc{
    [_tire release]//当销毁t的对象时,同时销毁b对象
    NSLog(@"Bike is disappear!");
    [super dealloc];
}
@end
#import <Foundation/Foundation.h>
#import "Bike.h"
#import "Tire.h"
 
int main(int argc, const char * argv[])
{
 
    @autoreleasepool {
        Tire *t = [[Tire alloc] init];
        Bike *b = [[Bike alloc] init];
        [t setPressure:22];
        [b setTire:t];
        [t release];
        NSLog(@"bike pressure is %d",[[b Tire] Pressure]);
        [b release];//把bike对象释放掉
    }
    return 0;
}
2014-04-27 21:32:35.049 MemoryLeakDemo[10957:303] bike pressure is 22
2014-04-27 21:32:35.051 MemoryLeakDemo[10957:303] Tire is disappear!
2014-04-27 21:32:35.051 MemoryLeakDemo[10957:303] Bike is disappear!

方法2:@synthesize @property实现

//  Tire.h
//  MemoryManage
 
 
#import <Foundation/Foundation.h>
 
@interface Tire : NSObject
{
    int pressure;
}
@property int pressure;
@end
//  Tire.m
//  MemoryManage
 
 
#import "Tire.h"
 
@implementation Tire
@synthesize pressure;
- (void) dealloc{
    NSLog(@"Tire is disappear!");
    [super dealloc];
}
@end
//  Bike.h
//  MemoryManage
 
#import <Foundation/Foundation.h>
#import "Tire.h"
@interface Bike : NSObject
{
    Tire *_tire;
}
@property (retain)Tire* _tire; //retain就能获得oneTire对象所有权
@end
//  Bike.m
//  MemoryManage
 
#import "Bike.h"
 
@implementation Bike
@synthesize _tire;
 
- (void) dealloc{
    [_tire release];
    NSLog(@"Bike is disappear!");
    [super dealloc];
}
@end
//  main.m
//  MemoryManage
 
#import <Foundation/Foundation.h>
#import "Bike.h"
#import "Tire.h"
 
int main(int argc, const char * argv[])
{
 
    @autoreleasepool {
        Tire *oneTire = [[Tire alloc] init];
        oneTire.pressure = 22;
        Bike *bike = [[Bike alloc] init];
        bike._tire = oneTire;
        [oneTire release];
        NSLog(@"bike is pressure %d",bike._tire.pressure);
        [bike release];
    }
    return 0;
}

结果:

2014-04-27 21:49:54.286 MemoryManage[11009:303] bike is pressure 22
2014-04-27 21:49:54.288 MemoryManage[11009:303] Bike is disappear!  --这里为什么是Bike先打印的?异步的?
2014-04-27 21:49:54.288 MemoryManage[11009:303] Tire is disappear!

不务正业之OC(四)–memory leak

创建两个类:Bike和Tire,自行车的其中一部件轮胎

//  Tire.h
//  MemoryLeakDemo
#import <Foundation/Foundation.h>
 
@interface Tire : NSObject
{
  int _pressure;//设置轮胎的胎压
}
 
- (void) setPressure:(int) pressure;//这边暂时不用property,synthesize
- (int) Pressure;
@end
//  Tire.m
//  MemoryLeakDemo
 
#import "Tire.h"
 
@implementation Tire
- (void) setPressure:(int) pressure{
    _pressure = pressure;
}
 
- (int) Pressure{
    return _pressure;
}
 
- (void) dealloc{
    NSLog(@"Tire is disappear!");
    [super dealloc];
}
@end
//  Bike.h
//  MemoryLeakDemo
 
#import <Foundation/Foundation.h>
@class Tire;
 
@interface Bike : NSObject
{
    Tire *_tire;
}
- (void) setTire:(Tire *) tire;
- (Tire *) Tire;
 
@end
//  Bike.m
//  MemoryLeakDemo
 
#import "Bike.h"
 
@implementation Bike
- (void) setTire:(Tire *) tire{
    _tire = tire;
}
 
- (Tire *) Tire{
    return _tire;
}
 
- (void) dealloc{
    NSLog(@"Bike is disappear!");
    [super dealloc];
}
@end
//  main.m
//  MemoryLeakDemo
 
#import <Foundation/Foundation.h>
#import "Bike.h"
#import "Tire.h"
 
int main(int argc, const char * argv[])
{
 
    @autoreleasepool {
        Tire *t = [[Tire alloc] init];
        Bike *b = [[Bike alloc] init];
        [t setPressure:22];
        [b setTire:t];
        [t release]; //释放t对象,导致t对象引用计数为0,对象销毁
        NSLog(@"bike pressure is %d",[[b Tire] Pressure]);//还在访问销毁的对象,Xcode5.1居然能成功访问?Xcode4.3肯定不行的呀。
    }
    return 0;
}

运行结果:
2014-04-27 20:51:53.447 MemoryLeakDemo[10810:303] Tire is disappear!
2014-04-27 20:51:53.449 MemoryLeakDemo[10810:303] bike pressure is 22