美文网首页
OC中重要的一些概念<三>

OC中重要的一些概念<三>

作者: imy博 | 来源:发表于2016-04-09 23:53 被阅读390次

    常用的结构体

    NSPoint和CGPoint

    • CGPoint和NSPoint是同义的
    • CGPoint代表的是二维平面中的一个点
      • 可以使用CGPointMake和NSMakePoint函数创建CGPoint

    NSSize和CGSize

    • CGSize和NSSize是同义的
    • CGSize代表的是二维平面中的某个物体的尺寸(宽度和高度)
      • 可以使用CGSizeMake和NSMakeSize函数创建CGSize

    NSRect和CGRect

    • CGRect和NSRect是同义的
    • CGRect代表的是二维平面中的某个物体的位置和尺寸
      • 可以使用CGRectMake和NSMakeRect函数创建CGRect

    常见的结构体使用注意

    • 苹果官方推荐使用CG开头的:
      • CGPoint
      • CGSize
      • CGRect

    NSNumber

    1.NSNumber基本概念

    • NSArray\NSDictionary中只能存放OC对象,不能存放int\float\double等基本数据类

    • 如果真想把基本数据(比如int)放进数组或字典中,需要先将基本数据类型包装成OC对象

    • NSNumber可以将基本数据类型包装成对象,这样就可以间接将基本数据类型存进NSArray\NSDictionary中

    2.NSNumber的创建

    • 以前

      • + (NSNumber *)numberWithInt:(int)value;
      • + (NSNumber *)numberWithDouble:(double)value;
      • + (NSNumber *)numberWithBool:(BOOL)value;
    • 现在

      • @10;
      • @10.5;
      • @YES;
      • @(num);

    3.从NSNumber对象中的到基本类型数据

    • - (char)charValue;
    • - (int)intValue;
    • - (long)longValue;
    • - (double)doubleValue;
    • - (BOOL)boolValue;
    • - (NSString *)stringValue;
    • - (NSComparisonResult)compare:(NSNumber *)otherNumber;
    • - (BOOL)isEqualToNumber:(NSNumber *)number;

    NSValue基本概念

    • NSNumber是NSValue的子类, 但NSNumber只能包装数字类型

    • NSValue可以包装任意值

      • 因此, 可以用NSValue将结构体包装后,加入NSArray\NSDictionary中

    常见结构体的包装

    • 为了方便 结构体 和NSValue的转换,Foundation提供了以下方法

    • 将结构体包装成NSValue对象

      • + (NSValue *)valueWithPoint:(NSPoint)point;
      • + (NSValue *)valueWithSize:(NSSize)size;
      • + (NSValue *)valueWithRect:(NSRect)rect;
    • 从NSValue对象取出之前包装的结构体
      • - (NSPoint)pointValue;
      • - (NSSize)sizeValue;
      • - (NSRect)rectValue;

    任意数据的包装

    • NSValue提供了下列方法来包装任意数据

      • + (NSValue *)valueWithBytes:(const void *)value objCType:(const char *)type;
      • value参数 : 所包装数据的地址
      • type参数 : 用来描述这个数据类型的字符串, 用@encode指令来生成
    • 从NSValue中取出所包装的数据

      • - (void)getValue:(void *)value;

    NSDate基本概念

    • NSDate可以用来表示时间, 可以进行一些常见的日期\时间处理

    • 一个NSDate对象就代表一个时间

    • [NSDate date]返回的就是当前时间

    日期时间对象

    • 结合NSCalendar和NSDate能做更多的日期\时间处理

    • 获得NSCalendar对象


    NSFileManager介绍

    • 什么是NSFileManager

      • 顾名思义, NSFileManager是用来管理文件系统的
      • 它可以用来进行常见的文件\文件夹操作
    • NSFileManager使用了单例模式

      • 使用defaultManager方法可以获得那个单例对象

    集合对象的内存管理

    • 当一个对象加入到集合(数组)中,那么该对象的引用计数会+1
    • 当集合(数组)被销毁的时候,集合(数组)会向集合(数组)中的元素发送release消息
    • 集合(数组)增加一个对象的方法名称是addObject:
    • 当一个对象加入到集合中,那么该对象的引用计数会+1
    • 当把一个对象从集合中移除时,会向移除的元素发送release消息
    • 集合(数组)移除一个对象的方法名称是removeObject:

    集合对象内存管理总结

    • 1.官方内存管理原则

      • 1> 当调用alloc、new、copy(mutableCopy)方法产生一个新对象的时候,就必须在最后调用一次release或者autorelease
      • 2> 当调用retain方法让对象的计数器+1,就必须在最后调用一次release或者autorelease
    • 2.集合的内存管理细节

      • 1> 当把一个对象添加到集合中时,这个对象会做了一次retain操作,计数器会+1
      • 2> 当一个集合被销毁时,会对集合里面的所有对象做一次release操作,计数器会-1
      • 3> 当一个对象从集合中移除时,这个对象会一次release操作,计数器会-1
    • 3.普遍规律

      • 1> 如果方法名是add\insert开头,那么被添加的对象,计数器会+1
      • 2> 如果方法名是remove\delete开头,那么被移除的对象,计数器-1

    copy基本概念

    • 什么是copy

      • Copy的字面意思是“复制”、“拷贝”,是一个产生副本的过程
    • 常见的复制有:文件复制

      • 作用:利用一个源文件产生一个副本文件
    • 特点:

      • 修改源文件的内容,不会影响副本文件
      • 修改副本文件的内容,不会影响源文件
    • OC中的copy

      • 作用:利用一个源对象产生一个副本对象
    • 特点:

      • 修改源对象的属性和行为,不会影响副本对象
      • 修改副本对象的属性和行为,不会影响源对象

    Copy的使用

    • 如何使用copy功能

      • 一个对象可以调用copy或mutableCopy方法来创建一个副本对象
      • copy : 创建的是不可变副本(如NSString、NSArray、NSDictionary)
      • mutableCopy :创建的是可变副本(如NSMutableString、NSMutableArray、NSMutableDictionary)
    • 使用copy功能的前提

      • copy : 需要遵守NSCopying协议,实现copyWithZone:方法
    @protocol NSCopying
    - (id)copyWithZone:(NSZone *)zone;
    @end
    
    • 使用mutableCopy的前提
      • 需要遵守NSMutableCopying协议,实现mutableCopyWithZone:方法
    @protocol NSMutableCopying
    - (id)mutableCopyWithZone:(NSZone *)zone;
    @end
    

    深复制和浅复制

    • 浅复制(浅拷贝,指针拷贝,shallow copy)
      • 源对象和副本对象是同一个对象
      • 源对象(副本对象)引用计数器+1,相当于做一次retain操作
      • 本质是:没有产生新的对象
        NSString *srcStr = @"lnj";
        NSString *copyStr = [srcStr copy];
        NSLog(@"src = %p, copy = %p", srcStr, copyStr);
    
    • 深复制(深拷贝,内容拷贝,deep copy)
      • 源对象和副本对象是不同的两个对象
      • 源对象引用计数器不变,副本对象计数器为1(因为是新产生的)
      • 本质是:产生了新的对象
        NSString *srcStr = @"lnj";
        NSMutableString *copyStr = [srcStr mutableCopy];
        NSLog(@"src = %p, copy = %p", srcStr, copyStr);
        NSLog(@"src = %@, copy = %@", srcStr, copyStr);
        [copyStr appendString:@" cool"];
        NSLog(@"src = %@, copy = %@", srcStr, copyStr);
    
        NSMutableString *srcStr = [NSMutableString stringWithFormat:@"lnj"];
        NSString *copyStr = [srcStr copy];
        [srcStr appendString:@" cool"];
        NSLog(@"src = %p, copy = %p", srcStr, copyStr);
        NSLog(@"src = %@, copy = %@", srcStr, copyStr);
    
        NSMutableString *srcStr = [NSMutableString stringWithFormat:@"lnj"];
        NSMutableString *copyStr = [srcStr mutableCopy];
        [srcStr appendString:@" cool"];
        [copyStr appendString:@" 520it"];
        NSLog(@"src = %p, copy = %p", srcStr, copyStr);
        NSLog(@"src = %@, copy = %@", srcStr, copyStr);
    
    • 只有源对象和副本对象都不可变时,才是浅复制,其它都是深复制

    copy与内存管理

    • 浅拷贝
      • 原对象引用计数器+1
      • 必须对原对象进行释放
      • 浅拷贝产生的副本对象和原对象是同一个对象
        char *cstr = "this is a c string";
        NSString *str1 = [[NSString alloc] initWithUTF8String:cstr];
        NSLog(@"str = %lu", [str1 retainCount]);
        NSString *str2 = [str1 copy];
        NSLog(@"str = %lu", [str1 retainCount]);
           [str2 release];必须做一次release //浅拷贝产生的副本对象和原对象是同一个对象
    
    • 深拷贝
      • 必须释放新对象
      • 深拷贝是产生了新的对象
        char *cstr = "this is a c string";
        NSString *str1 = [[NSString alloc] initWithUTF8String:cstr];
        NSLog(@"str = %lu", [str1 retainCount]);
        NSMutableString *str2 = [str1 mutableCopy];
        NSLog(@"str = %lu", [str1 retainCount]);
        [str2 release]; // 必须做一次release
    

    @property中的copy的作用

    • 防止外界修改内部的值
        @interface Person : NSObject
        @property (nonatomic, retain) NSString *name;
        @end
    
        NSMutableString *str = [NSMutableString stringWithFormat:@"lnj"];
    
        Person *p = [[Person alloc] init];
        p.name = str;
        // person中的属性会被修改
        [str appendString:@" cool"];
        NSLog(@"name = %@", p.name);
    
    • 防止访问对象对象已经释放
    • 不用copy情况
        Person *p = [[Person alloc] init];
        p.name = @"lnj";
        Dog *d = [[Dog alloc] init];
        d.age = 10;
        NSLog(@"retainCount = %lu", [d retainCount]); // 1
        p.pBlock = ^{
            // 报错, 调用之前就销毁了
            NSLog(@"age = %d", d.age);
        };
        [d release]; // 0
        p.pBlock();
        [p release];
    
    • 用copy情况
        Person *p = [[Person alloc] init];
        p.name = @"lnj";
        Dog *d = [[Dog alloc] init];
        d.age = 10;
        NSLog(@"retainCount = %lu", [d retainCount]); // 1
        p.pBlock = ^{
            // 会对使用到的外界对象进行一次retain
            NSLog(@"age = %d", d.age);
            NSLog(@"retainCount = %lu", [d retainCount]); // 1
        };
        [d release]; // 1
        p.pBlock();
        [p release];
    

    @property内存管理策略选择

    • 非ARC

      • 1> copy : 只用于NSString\block
      • 2> retain : 除NSString\block以外的OC对象
      • 3> assign :基本数据类型、枚举、结构体(非OC对象),当2个对象相互引用,一端用retain,一端用assign
    • ARC

      • 1> copy : 只用于NSString\block
      • 2> strong : 除NSString\block以外的OC对象
      • 3> weak : 当2个对象相互引用,一端用strong,一端用weak
      • 4> assgin : 基本数据类型、枚举、结构体(非OC对象)

    // MRC, A对象想拥有B对象, 需要对B对象进行一次retain
    //      A对象不用B对象了, 需要对B对象进行一次release
    //      property的时候进行retain, dealloc的时候进行release
    
    // ARC, A对象想拥有B对象, 那么就需要用一个强指针指向B对象
    //      A对象不用B对象了, 什么都不需要做, 编译器会自动帮我们做
    
    // 在ARC中保存一个对象用strong, 相当于MRC中的retain
            
            @property(nonatomic, strong)Dog *dog;
    

    自定义类实现copy操作

    • 让类遵守NSCopying协议

    • 实现 copyWithZone:方法,在该方法中返回一个对象的副本即可。

    • 在copyWithZone方法中,创建一个新的对象,并设置该对象的数据与现有对象一致, 并返回该对象.

      • zone: 表示空间,分配对象是需要内存空间的,如果指定了zone,就可以指定 新建对象对应的内存空间。但是:zone是一个非常古老的技术,为了避免在堆中出现内存碎片而使用的。在今天的开发中,zone几乎可以忽略

    • 无父类实现

    -(id)copyWithZone(NSZone *)zone{
    
       CustomMode *custom = [[[self class]  copyWithZone:zone]  init];
    
       Custom ->_a = [_a copyWithZone:zone];
    
       Custom -> _c = _c;//不是对象的 直接赋值
    
       Return custom;
    
    }
    
    • 有父类实现
      • 不调用父类方法, 无法拷贝父类中继承的属性
      • 不重新父类copyWithZone, 无法拷贝本来中的特有属性
    -(id)copyWithZone(NSZone *)zone{
    
        CustomModel *custom = [super copyWithZone:zone];
        ….
        Return custom;
    }
    

    单例模式概念

    • 什么是单例模式:(Singleton)

      • 类的对象成为系统中唯一的实例,提供一个访问点,供客户类 共享资源单例就是无论怎么创建都只能有一个实例对象
    • 什么情况下使用单例?

      • 1、类只能有一个实例,而且必须从一个为人熟知的访问点对其进行访问,比如工厂方 法。
      • 2、这个唯一的实例只能通过子类化进行扩展,而且扩展的对象不会破坏客户端代码。
    • 创建单例对象的方法一般以什么开头?

      • 1.一般情况下创建一个单例对象都有一个与之对应的类方法
      • 2.一般情况下用于创建单例对象的方法名称都以share开头, 或者以default开头

    单例宏抽取

    • 单例通过宏定义的方式提取,主要目的是为了方便调用复杂的单例模式的代码,单例宏提取分为MRC和ARC两种模式下的提取,这两种模式下的提取是有区别的

    相关文章

      网友评论

          本文标题:OC中重要的一些概念<三>

          本文链接:https://www.haomeiwen.com/subject/aueblttx.html