52个编写高质量iOS有效方法(41-50)

倒计时回家还剩下两天

1.在OC中如果有多个线程想使用同一份代码,那么多线程读写可能会出现问题。这时候需要对某一个对象进行加锁操作。@synchronized可以实现这种加锁,但是效率非常低,同样的NSLock与NSRecurisiveLock也是可以实现这种加锁操作,但是效率不高。一种比较推崇的是GCD。下面是具体的实现代码

_syncQueue = dispatch_get_global_create("DISPATCH_QUEUE_PRIORITY_DEFAULT",NULL);  
-(NSString*) someString {  
    __block NSString* localSomething;  
    dispatch_sync(_syncQueue,^{  
        localSomeString = _someString;  
    });  
    return localSomeString  
}  
-(void) setSomeString:(NSString*) someString{  
    dispatch_barrier_async(_syncQueue,^{  
        _someString = someString;  
    });  
} 

2.尽量少用performSeletor,因为这个方法可以添加的方法参数有限。而且performseletor再ARC环境下,内存管理方面有缺失。因此如果想使用这种动态绑定方法,可以选择使用NSInvocation,自己封装一个对象跟调用方法,然后进行消息转发。如果想延迟几秒调用一个函数注意下面的写法:

不推荐:
[self performSelector:@selector(show) withObject:nil afterDelay:0.4];
推荐:
dispatch_time_t = dispatch_time(DISPATCH_TIME_NOW,(int64_t)(0.4*NSEC_PER_SEC));
dispatch_after(time,dispatch_get_main_quene(),^(){[self show] });

如果想吧任务放在主线程上面,也可以选择下面两种方法:

不推荐: [self performSelectorOnMianThread:@selector(doSomething) withObject:nil waitUntilDone:No];
推荐:
dispatch_async(dispatch_get_main_quene(),^({self doSemthing}));

3.很少有其他技术能与gcd的同步机制相媲美。对于那些只需要执行一次的代码来说,也是如此,使用gcd的dispatch_once最为方便。然而在执行后台任务时候,gcd并不一定是最佳方式。还有一种技术叫做NSOpertationQueue,它虽然与gcd不同,但是却与之相关,开发者可以把操作以NSOpertation子类的形式放到队列中,这些操作也能够并发执行。

在两者差别中,首先要注意:gcd是纯c的API,而操作队列是OC对象。gcd处理轻量级block而操作队列处理重量级OC对象。

用NSOperationQueue类的addOperatonWithBlock方法搭配NSBlockOperation类来操作队列,其语法与纯gcd方法非常类似。使用NSOperation和NSOpertaionQueue的好处如下:

● 取消某个操作

● 指定操作间的依赖关系

● 通过键值观测机制监控NSOperation属性。

● 指定操作的优先级

● 重用NSOperation对象。

操作队列很多地方胜过派发队列。操作队列提供了很多执行任务的方法,而且都是写好了,直接就能用。开发者不用再编写复杂的调度器。

NSNotificationCenter使用了操作队列

本节要点

● 在解决多线程与任务管理问题时,派发队列并非唯一方案。

● 操作队列提供了一套高层次的OC API。能实现纯gcd所具备的绝大部分功能,而且还能完成一些更为复杂的操作,那些操作如果该用gcd来实现,则需要另外写代码。

4.简单讲了一下dispatch_group的用法,用来封装一组操作。只有当这个组中所有的任务都执行完成之后会有一个通知,然后继续做后面操作。

5.直接看代码吧,通常是单例的实现。

+(id) sharedInstance{  
    static EOCClass *sharedInstance = nil;  
    static dispatch_once_t onceToken;  
dispatch_once(&onceToken,^{sharedInstance = [[self alloc]init];});  
return sharedInstance;  
}  

6.不要使用dispatch_get_current_queue 原因如下:

  • dispatch_get_current_queue 函数的行为通常与开发者的预期不一致,这个函数已经废弃了,只做调试用。
  • 这个函数通常用来解决不可重入的代码所引发的死锁,然而如果可以用这个函数来解决的问题,通常也可以用特定的队列来解决。

7.熟悉系统框架,并没有讲什么东西

8.只是作为一个建议,多用块枚举,少用for循环

9.上面提到过Foundation框架和CoreFoundation框架,Foundation中NSArray等collection,CoreFoundation中也有对应的CFArray,这两种创建数组的方式也许有区别,然而“无缝桥接”技术可以使得这两个类型之间平滑互转。下面代码演示了简单的无缝桥接:

NSArray *anNSArray = @[@1,@2,@3,@4,@5];  
CFArrayRef aCFArray = (__bridge CFArrayRef)anNSArray;  
NSLog(@"size of array =%li",CFArrayGetCount(aCFArray)); 

__bridge本身的意思是:ARC仍然具备这个OC对象的所有权

10.构建缓存时选用NSCache而非NSDictionary
NSCache比NSDictonary好的地方是:当系统资源将要耗尽时,它可以自动删减缓存(删减“最近未使用的对象”)。下面这段代码演示了缓存的用法:

#import   
  
//network fetcher class  
typedef void(^EOCNetworkFetcherCompletionHandler)(NSData* data);  
@interface EOCNetworkFetcher : NSObject  
-(id)initWithURL(NSURL*)url;  
-(void)startWithCompletionHandler:(EOCNetworkFetcherCompletionHandle)handler;  
@end  
  
// class that uses the network fetcher and caches results  
@interface EOCClass :NSObject  
@end  
@implementation EOCClass{  
    NSCache* _cache;  
}  
-(id)init{  
    if(self = [super init]){  
        _cache = [NSCache new];  
        //cache a maximum of 100 URLs  
        _cache.countLimit = 100;  
        //the size in bytes of data is used as the cost,so this sets a cost limit of 5MB  
        _cache.totalCostLimit = 5*1024*1024;  
    }  
    return self;  
}  
-(void) downloadDataForUrl:(NSURL*)url{  
    NSData *cachedData = [_cache objectForKey:url];  
    if(cachedData){  
    //cached it  
    [self useData:cacheData];  
}else{  
    //cache miss  
    EOCNetworkFetcher* fetcher = [[EOCNetworkFetcher alloc] initWithURL:url]  
    fetcher startWithCompletionHandler:^(NSData* data){  
        [_cache setObject:data forKey:url cost:data.length];  
        [self useData:data];  
        }];  
    }  
}  
@end  

创建NSCache时,将其中可缓存的对象数目设定为100,将“总开销”上限设为5MB

你可能感兴趣的:(52个编写高质量iOS有效方法(41-50))