不务正业之OC(十二) 单例设计模式

单例设计模式:只能创建一个实例

什么时候创建单例:
1、单例对象作为全局数据,可以为其他对象访问
2、如果创建对象时,需要init要做很多事情,那么创建单例可以提高性能

创建单例步骤:
1、创建一个对象的静态实例,初始化为nil
2、当类的实例为nil时,创建类工厂方法
3、覆盖allocWithZone方法,alloc时不会产生新对象
4、实现NSCopying协议,覆盖release、autorelease、retain、retainCount方法,确保单例
5、多线程情况下,@synchronized,保证单例正确初始化

//  Lijie.h
//  Single
 
#import <Foundation/Foundation.h>
 
@interface Lijie : NSObject<NSCopying>
 
@property(nonatomic,retain) NSNumber *age;
@property(nonatomic,retain) NSString *sex;
 
+ (id)sharePerson;
 
@end
 
//  Lijie.m
//  Single
 
#import "Lijie.h"
 
static Lijie *singleLijie = nil;
 
@implementation Lijie
 
+ (id)sharePerson{
    @synchronized(self){
        if (singleLijie == nil) {
            singleLijie = [[[self class] alloc] init];
        }
        return singleLijie;
    }
}
 
+ (id) allocWithZone:(NSZone *)zone{
    if (singleLijie == nil) {
        singleLijie = [super allocWithZone:zone];
    }
    return singleLijie;
}
 
- (id)copyWithZone:(NSZone *)zone{
    return singleLijie;
}
 
- (id)retain{
    return singleLijie;
}
 
- (oneway void)release{
}
 
- (id)autorelease{
    return singleLijie;
}
 
- (NSUInteger) retainCount{
    return UINT_MAX;
}
 
 
@end
 
//  main.m
//  Single
 
#import <Foundation/Foundation.h>
#import "Lijie.h"
 
int main(int argc, const char * argv[])
{
 
    @autoreleasepool {
        Lijie *lijie = [Lijie sharePerson];
 
        Lijie *lijie1 = [[Lijie alloc] init];
        Lijie *lijie2 = [Lijie sharePerson];
        Lijie *lijie3 = [lijie1 copy];
 
        [lijie release];
        [lijie release];
        [lijie release];
        [lijie release];
        [lijie release];
        NSLog(@"");//这里搞个breakpoint可以观察lijie1、lijie2、lijie3三个对象地址
    }
    return 0;
}

1

不务正业之OC(十一)–复制对象之深浅Copy

浅Copy只复制对象本身,不对对象属性进行复制。foundatio框架中支持对象Copy的,默认是浅Copy。

#import <Foundation/Foundation.h>
 
int main(int argc, const char * argv[])
{
 
    @autoreleasepool {
        NSMutableArray *array = [[NSMutableArray alloc] init];
        for (int i = 1; i < 3; i++) {
            NSObject *obj = [[NSObject alloc] init];
            [array addObject:obj];
            [obj release];
        }
 
        for (NSObject *o in array) {
            NSLog(@"address:%@,retain count:%lu",o,(unsigned long)o.retainCount);
        }
 
        NSMutableArray *arraycopy = [array copy];
        for (NSObject *b in arraycopy) {
            NSLog(@"address:%@,retain count:%lu",b,(unsigned long)b.retainCount);
        }
    return 0;
    }
}
2014-05-03 12:00:44.643 Objcopy[15694:303] address:<NSObject: 0x1002022c0>,retain count:1
2014-05-03 12:00:44.645 Objcopy[15694:303] address:<NSObject: 0x100201b30>,retain count:1
2014-05-03 12:00:44.645 Objcopy[15694:303] address:<NSObject: 0x1002022c0>,retain count:2
2014-05-03 12:00:44.646 Objcopy[15694:303] address:<NSObject: 0x100201b30>,retain count:2

可以发现原对象的地址没发生变化,只是引用计数加1

浅Copy:

//  My.h
//  Copytest
 
#import <Foundation/Foundation.h>
 
@interface My : NSObject<NSCopying>
 
@property(nonatomic,retain) NSString* name;
@property(nonatomic,assign) NSNumber* age;
 
@end
 
//  My.m
//  Copytest
 
#import "My.h"
 
@implementation My
 
//浅Copy
- (id)copyWithZone:(NSZone *)zone{
    My *my = [[[self class] allocWithZone:zone] init];
    my.name = _name;
    my.age = _age;
    return my;
}
@end
 
//  main.m
//  Copytest
#import <Foundation/Foundation.h>
#import "My.h"
 
int main(int argc, const char * argv[])
{
 
    @autoreleasepool {
        My *my = [[My alloc] init];
        my.name = @"lijie";
        my.age = @31;
 
        My *my2 = [my copy];
        NSLog(@"%my is address:%p",my);
        NSLog(@"%my2 is address:%p",my2);
 
        NSLog(@"my name address:%p",my.name);
        NSLog(@"my2 name address:%p",my2.name);    
    }
    return 0;
}
//浅Copy的属性变量name指向同一个地址
2014-05-03 12:57:28.264 Copytest[16051:303] my is address:0x100202340
2014-05-03 12:57:28.266 Copytest[16051:303] my2 is address:0x1002033f0
2014-05-03 12:57:28.266 Copytest[16051:303] my name address:0x1f27
2014-05-03 12:57:28.267 Copytest[16051:303] my2 name address:0x1f27

深Copy
只修改copyWithZone方法

#import "My.h"
 
@implementation My
//浅Copy
- (id)copyWithZone:(NSZone *)zone{
    My *my = [[[self class] allocWithZone:zone] init];
    my.name = [_name mutableCopy];//Foundation可复制对象,当我们Copy一个不可变对象时,作用就是retain,cocoa做内存优化。使用mutableCopy,无论对象是否可变,副本是可以变,就实现真正的Copy。Copy可变的对象时,当副本是不可变,也实现Copy
    my.age = [_age copy];
    return my;
}
@end
 
2014-05-03 15:01:59.308 Copytest[16189:303] my is address:0x100203f00
2014-05-03 15:01:59.309 Copytest[16189:303] my2 is address:0x100202ae0
2014-05-03 15:01:59.310 Copytest[16189:303] my name address:0x1000022f0 //地址不一样
2014-05-03 15:01:59.310 Copytest[16189:303] my2 name address:0x100204560

不务正业之OC(十)–复制对象之retain与copy区别

复制对象:创建一副本,开辟一块新的内存空间
实现协议:NSCopying或NSMutableCopying其中之一
注意:Copy产生对象不可变、MutableCopy产生对象可变

//  main.m
//  Objcopy
 
#import <Foundation/Foundation.h>
 
int main(int argc, const char * argv[])
{
 
    @autoreleasepool {
        NSMutableArray *muarray = [NSMutableArray arrayWithObjects:@"a",@"b",@"c",nil];
        NSMutableArray *retain_array = [muarray retain];
        [retain_array removeLastObject];
        for (NSString *member in muarray){
            NSLog(@"member is %@",member);
        }
        NSLog(@"retain count %lu",(unsigned long)muarray.retainCount);
        [muarray release];
        NSLog(@"retain count %lu",(unsigned long)muarray.retainCount);
 
        NSLog(@"-----------------------");
        NSMutableArray *muarray2 = [NSMutableArray arrayWithObjects:@"a",@"b",@"c",nil];
        NSMutableArray *copy_array = [muarray2 mutableCopy];
        [copy_array removeLastObject];
        for (NSString *member in muarray2){
            NSLog(@"member is %@",member);
        }
 
    }
    return 0;
}

Copy和NSMutableCopy区别

#import <Foundation/Foundation.h>
 
int main(int argc, const char * argv[])
{
 
    @autoreleasepool {
        NSArray *array1 = [NSArray arrayWithObjects:@"a",@"b",nil];
        NSMutableArray *array2 = [NSMutableArray arrayWithObjects:@"a",@"b",nil];
        [array1 addObject:"c"];//这行代码直接崩溃
        [array2 addObject:@"c"];
        NSLog(@"%@",array2);
    }
    return 0;
}

不务正业之OC(九)–类目

不务正业之OC(九)–类目

因为OC中不支持多重继承,对于需要增加方法,就比较麻烦,所以有了类目。

介绍:
1、类目定义的方法,成为原始类的一部分,调用没有区别
2、父类定义的类目,子类可以继承

作用:
1、对现在有类进行扩展
2、子类代替手段
3、类中方法归类(可以定义到多个文件中去)

局限:
1、不能添加实例变量
2、建议不要cover原始类的中方法,类目方法具有最高优先级

介绍两种类目实现
1、把类目定义和类定义放在一起
2、类目定义放在单独的文件

第一种方式:

//  Child.h
//  Catagory
 
 
#import <Foundation/Foundation.h>
 
@interface Child : NSObject
{
    NSString *_name;
    int _age;
}
@property (nonatomic,retain) NSString* _name;
@property (nonatomic,assign) int _age;
//类中方法
- (void) cry;
 
@end
//类目定义,Creation为类目名。规则:类名 (类目名)
@interface Child (Creation)
 
- (id) initWithName:(NSString *) name setAge:(int) age;
 
@end
//再定义一个类目Grow
@interface Child(Grow)
 
- (void) eat;
 
@end
 
//  Child.m
//  Catagory
 
#import "Child.h"
 
@implementation Child
 
@synthesize _name;
@synthesize _age;
 
- (void) cry{
    NSLog(@"child is crying!");
}
 
@end
 
@implementation Child (Creation)
 
- (id) initWithName:(NSString *) name setAge:(int) age{
    self._name = name;
    //一定要release,因为是以retain创建的
    [name release];
    self._age = age;
    return self;
}
 
@end
 
@implementation Child(Grow)
 
- (void) eat{
    NSLog(@"child want to eat!");
}
 
@end
 
 
//  main.m
//  Catagory
 
#import <Foundation/Foundation.h>
#import "Child.h"
 
int main(int argc, const char * argv[])
{
 
    @autoreleasepool {
        NSString *name = [NSString stringWithFormat:@"liyi"];
        Child *child = [[Child alloc] initWithName:name setAge:1];
        [child cry];//实例方法调用
        NSLog(@"My son name is:%@,age is %d",child._name,child._age);//类目方法调用
        [child eat];//类目方法调用
    }
    return 0;
}

结果:

2014-05-02 22:35:45.250 Catagory[15168:303] child is crying!
2014-05-02 22:35:45.252 Catagory[15168:303] My son name is:liyi,age is 1
2014-05-02 22:35:45.252 Catagory[15168:303] child want to eat!

第二种方式:
因为在Xcode就有类目创建选项,非常方便
1

不务正业之OC(八)–观察者模式–notification

通知:类和类之间可以相互通讯,存在多对多,不像委托设计一对一,比较清晰,所以在使用类和类通讯时,建议使用委托代理模式

//  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;
        [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(timerAction:) userInfo:nil repeats:YES];
    }
    return self;
}
 
- (void) timerAction:(NSTimer *)timer{
    self.wawa--;
    NSLog(@"wawa:%ld",_wawa);
    if (_wawa < 16) {
        //定义通知中心,并发送通知,通知名为weak_up
        [[NSNotificationCenter defaultCenter] postNotificationName:@"weak_up" object:[NSNumber numberWithInteger:_wawa]];
        [timer invalidate];
    }
}
 
@end
//  Mother.h
 
#import <Foundation/Foundation.h>
#import "Baby.h"
 
@interface Mother : NSObject
@end
 
//  Mother.m
 
#import "Mother.h"
 
@implementation Mother
 
- (id) init{
    if(self = [super init]){
        //接收通知者
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(weakNotification:) name:@"weak_up" object:nil];
    }
    return self;
}
//通知接到后,调用方法
- (void)weakNotification:(NSNotification *)notification{
    NSNumber *num = notification.object;
    NSLog(@"Baby weak:%@",num);
}
 
@end
//  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] init];
        [[NSRunLoop currentRunLoop] run];
    }
    return 0;
}

运行结果:

2014-04-30 22:00:19.679 KVO[13898:303] wawa:19
2014-04-30 22:00:20.679 KVO[13898:303] wawa:18
2014-04-30 22:00:21.679 KVO[13898:303] wawa:17
2014-04-30 22:00:22.680 KVO[13898:303] wawa:16
2014-04-30 22:00:23.680 KVO[13898:303] wawa:15
2014-04-30 22:00:23.680 KVO[13898:303] Baby weak:15