zoukankan      html  css  js  c++  java
  • effective OC2.0 52阅读笔记(七 系统框架)

    47 熟悉系统框架 总结:

    将代码封装为动态库,并提供接口的头文件,就是框架。平时的三方应用都用静态库(因为iOS应用程序不允许在其中包含动态库),并不是真正的框架,然而也经常视为框架。例如:NSLinguisticTagger可以解析字符串并找到其中的全部名词、动词、代词等。

    无缝桥接:将CoreFoundation中的C语言数据结构平滑转换为Foundation中的Objective-C对象,也可反向转换。

    OC编程一个重要特点是,经常需要使用底层的C语言级API,用C语言来实现API的好处是,可以绕过OC的运行期系统,从而提升执行速度。

    coreAnimation是OC写成的,是QuartzCore框架的一部分。CoreGraphics框架以C语言写成。很多常见任务都能用框架来做。

    48 多用块枚举,少用for循环 总结:

    四种方式:

    一for循环(反向遍历时,使用for循环会比其它方式简单许多)

    二NSEnumerator(OC1.0枚举器)

    抽象基类,指定义了两个方法,-(NSArray *)allObjects;和- (id)nextObject;

    Foundation框架中的内建的collection类都实现了这种便利方式。

    NSArray *anArray = /**/;

    NSEunmerator *enumerator = [anArray objectEnumberator];//字典就是 [aDictionary keyEnumerator]; 反向遍历的话用reverseObjectEnumerator

    id object;

    while((object = [enumberator nextObject])!==nil){

    }

    三快速遍历(OC2.0快速枚举)(同枚举器来历差不多,语法更简洁)

    如果某各类要支持快速遍历可以宣称支持NSFastEumeration协议(只有一个方法):

    - (void)enumerateObjectsAtIndexes:(NSIndexSet *)s options:(NSEnumerationOptions)opts usingBlock:(void (NS_NOESCAPE ^)(ObjectType obj, NSUInteger idx, BOOL *stop))block NS_AVAILABLE(10_6, 4_0);

    NSEunmerator也实现了NSFastEumeration协议,所以能用来执行反向遍历,如下:

    for (id object in [arr reverseObjectEnumerator])

    四基于块的遍历遍历时既能获取对象,也能知道其下标。还可以终止遍历操作。

    对于数组:

    - (void)enumerateObjectsUsingBlock:(void (NS_NOESCAPE ^)(ObjectType obj, NSUInteger idx, BOOL *stop))block NS_AVAILABLE(10_6, 4_0);

    - (void)enumerateObjectsWithOptions:(NSEnumerationOptions)opts usingBlock:(void (NS_NOESCAPE ^)(ObjectType obj, NSUInteger idx, BOOL *stop))block NS_AVAILABLE(10_6, 4_0);

    对于字典:(可以同时得到键与值,这很可能比其它方式快很多,因为在字典内部的数据结构中,键与值本来就是存储在一起的)

    - (void)enumerateKeysAndObjectsUsingBlock:(void (NS_NOESCAPE ^)(KeyType key, ObjectType obj, BOOL *stop))block NS_AVAILABLE(10_6, 4_0);

    - (void)enumerateKeysAndObjectsWithOptions:(NSEnumerationOptions)opts usingBlock:(void (NS_NOESCAPE ^)(KeyType key, ObjectType obj, BOOL *stop))block NS_AVAILABLE(10_6, 4_0);

    对于集合:

    - (void)enumerateObjectsUsingBlock:(void (NS_NOESCAPE ^)(ObjectType obj, BOOL *stop))block NS_AVAILABLE(10_6, 4_0);

    - (void)enumerateObjectsWithOptions:(NSEnumerationOptions)opts usingBlock:(void (NS_NOESCAPE ^)(ObjectType obj, BOOL *stop))block NS_AVAILABLE(10_6, 4_0);

    块还可以修改方法签名,知道待遍历的collection含有何种对象,指出对象的具体类型(效果上相当于把本来需要执行的类型转换操作给块方法签名来做)。

    NSEnumerationOptions取值可用按位或连接。可通过NSEnumerationConcurrent使得块(传入选项掩码)通过GCD来并发执行遍历操作。反向遍历通过NSEnumerationReverse来完成。无须另行编码。

    49 对自定义其内存管理语义的collection使用无缝桥接 总结:

    __bridge,__bridge_retained,__bridge_transfer。coreFoundation框架中的称为数据结构。

    id objc = [[NSObject alloc]init];

    void *p= (__bridge_retained void *)objc;// (__bridge_retained CF type)

    id o = (__bridge_transfer id)p;//(__bridge_transfer OC type)

    通过无缝桥接技术,可以在Foundation框架中的OC对象与CoreFoundation框架中的c语言数据结构之间来回转换。在CoreFoundation层面创建collection时,可以指定许多回调函数,这些函数表示此collection应如何处理其元素。然后,可运用无缝桥接技术,将其转换成具备特殊内存管理语义的OC collection。(有时候Key是不支持拷贝操作的)

    举例:

    CFMutableDictionary创建

    CFMutableDictionaryRef CFDictionaryCreateMutable(

      CFAllocatorRef allocator,   //内存分配器 CoreFoundation对象里的数据结构需要占用内存,而分配器负责分配及回收这些内存,NULL为默认分配器。

      CFIndex capacity,  //字典初始大小

      const CFDictionaryKeyCallBacks *keyCallBacks,//指示字典中的键和值在遇到各种事件时应该执行何种操作。

      const CFDictionaryValueCallBacks *valueCallBacks

    );

    以下是回调的具体结构体,定义了许多回调函数:

    typedef struct {

        CFIndex version;

        CFDictionaryRetainCallBack retain;

        CFDictionaryReleaseCallBack release;

        CFDictionaryCopyDescriptionCallBack copyDescription;

        CFDictionaryEqualCallBack equal;

        CFDictionaryHashCallBack hash;

    } CFDictionaryKeyCallBacks;

    typedef struct {

        CFIndex version;

        CFDictionaryRetainCallBack retain;

        CFDictionaryReleaseCallBack release;

        CFDictionaryCopyDescriptionCallBack copyDescription;

        CFDictionaryEqualCallBack equal;

    } CFDictionaryValueCallBacks;

    实例:

    const void * SXHRetainCallback (CFAllocatorRef allocator, const void *value)

    {

        return CFRetain(value);

    }

    void    SXHReleaseCallBack(CFAllocatorRef allocator, const void *value)

    {

        CFRelease(value);

    }

    CFDictionaryKeyCallBacks keyCallbacks = {

            0,

            SXHRetainCallback,

            SXHReleaseCallBack,

            NULL,

            CFEqual,

            CFHash,

            

        };

        

        CFDictionaryValueCallBacks valueCallbacks = {

            0,

            SXHRetainCallback,

            SXHReleaseCallBack,

            NULL,

            CFEqual,

        };

        

        CFMutableDictionaryRef aCFDictionary = CFDictionaryCreateMutable(NULL, 0, &keyCallbacks, &valueCallbacks);

        

        NSMutableDictionary *anDictionary = (__bridge_transfer NSMutableDictionary*)aCFDictionary;//键和值皆是保留状态

    50 构建缓存时选用NSCache而非NSDictionary 总结:

    NSCache的好处:当系统资源将要耗尽时,可以自动删减缓存,还会先行删减最久未使用的对象。而且开发者可以操控缓存删减其内容的时机。有两个与系统资源相关的尺度可供调整,其一是缓存中的对象总数,其二是对象的总开销。(但是这些限制仅是对NSCache起指导作用)。

    与字典不同,不会拷贝键,而是保留键。线程安全。

    缓存的本意是增加应用程序响应用户操作的速度。

    ////如果存在缓存则使用缓存的数据,如果没有缓存,则重新下载数据

    //- (void)downloadDataForUrl:(NSURL *)url{

    //    NSData *cacheData = [_cache objectForKey:url];

    //    if (cacheData) {

    //        [self useData:cacheData];

    //    }

    //    else{

    //        SMNetworkFetcher *fetcher = [[SMNetworkFetcher alloc]initWithUrl:url];

    //        [fetcher startWithCompletionHandler:^(NSData *data){

    //            [_cache setObject:data forKey:url cost:data.length];

    //            [self useData:data];

    //        }];

    //    }

    //}

     /*使用NSPurgeableData作为缓存对象,与NSCache搭配使用,可实现自动清除数据的功能。当NSPurgeableData对象所占内存为系统所丢弃时,该对象自身也会从缓存中移除。*/

    - (void)downloadDataForUrl:(NSURL *)url{

        NSPurgeableData *cacheData = [_cache objectForKey:url];

        if (cacheData) {

            [cacheData beginContentAccess];

            [self useData:cacheData];

            [cacheData endContentAccess];

        }

        else{

            SMNetworkFetcher *fetcher = [[SMNetworkFetcher alloc]initWithUrl:url];

            [fetcher startWithCompletionHandler:^(NSData *data){

                NSPurgeableData *cacheData = [NSPurgeableData dataWithData:data];

                [_cache setObject:cacheData forKey:url cost:data.length];

    //            [cacheData beginContentAccess];

                //创建purgeable对象之后,purge引用计数会多1,所以无需再调用beginContentAccess

                [self useData:data];

                [cacheData endContentAccess];

            }];

        }

    注意:只有那种“重新计算起来很费事的”数据,才值得放入缓存,比如需要从网络获取或从磁盘读取的数据。

    51 精简initialize与load的实现代码 总结:

    load:对于加入运行期系统中的每个类及分类来说,在应用程序启动时,必定会调用此方法,先调用类中的再调用分类的,先执行超类的load方法,再执行子类的,而且仅调用一次。在load中使用其他类是不安全的(因为根据某个给定的程序库,是无法判断出其中各个类的载入顺序的)。因此load方法的实现要精简一些,因为整个应用程序在执行load方法时都会阻塞。(注意:load方法并不像普通方法那样,并不遵从那套继承规则(load方法不参与覆写机制),如果某个类本身没实现load方法,那么不管其各个级超类是否实现此方法、系统都不会调用。)(用途:可以在分类中编写此方法判断分类是否正确载入系统中)

    initialize:首次调用该类之前调用,且仅调用一次。是由运行期系统来调用,绝不应该通过代码直接调用。它是惰性调用的。如果本类未实现,而其超类实现了,就会运行其超类的实现代码,遵循继承规则。

    initialize与load区别

    1:应用程序无须把每个类的initialize都执行一遍。而load必须阻塞并等待所有类的load都执行完。

    2:运行期系统执行该方法时是处于常态的。可确保initialize方法一顶会在线程安全的环境中执行。

    3:首次使用某个类之前,系统会向其发送intialize消息,由于此方法遵从普通的覆写规则,所以通常应该在里面判断当前要初始化的是哪个类。

    所以一般这样写initialize方法

    +(void)initialize{

      if(self == [EOCBaseClass class]){

        //blahblah

      }

    }

    load与initialize方法都应该实现的精简写,这有助于保持应用程序的响应能力,也能减少引入“依赖环”的几率。

    无法在编译器设定的全局常量,可以放在initialize方法里初始化。例如:static NSMutableArray *kSomeObjects;还有单例类也可以这样做。

    52 别忘了NSTimer会保留其目标对象 总结:

    只有把计时器放在运行循环里,它才能正常触发任务。(NSTimer其实是将一个监听加入到系统的runloop中去,当timer执行完,timer会再一次将自己加入到runloop中去继续监听,一个timer对象同一时间只能被注册到一个runloop中去,尽管在这个runloop中它能够被添加到多个runloop中去。CFRunloopTimerRef与NSTimer可以互换)

    计时器会保留其target对象,等到自身失效时再释放此对象。(1)重复任务时,调用invalidate方法可令计时器失效。(2)执行完相关任务后,一次性的计时器也会失效。

    反复执行任务的计时器,很容易引入保留环,如果这种计时器的目标对象又保留了计时器本身,那肯定会导致保留环,这种环装保留关系,可能是直接发生的,也肯能是通过对象图里的其他对象间接发生的。可以扩充NSTimer的功能,用块来打破保留环。不过,除非NSTimer将来在公共接口里提供此功能,否则必须创建分类,将相关实现代码加入其中。方法:

    @interface NSTimer (EOCBlockSupport)

    +(NSTimer *)eoc_scheduledTimerWithTimeInterval:(NSTimeInterval)interval block:(void(^)())block repeats:(BOOL) repeats;

    @end

    //iOS10.0之后已经实现了该功能

    @implementation NSTimer (EOCBlockSupport)

    +(NSTimer *)eoc_scheduledTimerWithTimeInterval:(NSTimeInterval)interval block:(void(^)())block repeats:(BOOL) repeats

    {
      return [self scheduledTime....]

    }

    @end

  • 相关阅读:
    spring websocket 记录
    mysql-enum
    再问jvm内存管理
    video相关参数、操作和事件
    监听页面关闭和刷新的总结
    VUE路由新页面打开的方法总结
    VUE的一个数据绑定与页面刷新相关的bug
    element-ui笔记
    Vue笔记(props和 mounted)
    Python总结(二)
  • 原文地址:https://www.cnblogs.com/encoreMiao/p/5126770.html
Copyright © 2011-2022 走看看