热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

EffectiveObjective-C(第47-52条)系统架构,foundation、for-in、NSTimer

第47条:熟悉系统框架若是不了解系统架构所提供的内容,那么就可能会把其中已经实现的东西再写一遍。将一系列代码封装为动态库(dynamiclibrary),并在其中放入描述其接口的头文
第47条:熟悉系统框架

        若是不了解系统架构所提供的内容,那么就可能会把其中已经实现的东西再写一遍。将一系列代码封装为动态库(dynamic library),并在其中放入描述其接口的头文件,这样做出来的东西就叫框架。然而iOS应用程序不允许在其中包含动态库。

        开发者使用最对的是Foundation框架,像NSObject、NSArray、NSDictionary等类都在其中。Foundation框架中的类使用NS前缀,此前缀是OC语言作为NeXTSPET操作系统的编程语言首度确定的。Foundation真可谓OC应用程序的基础,Foundation不仅提供了collection等基础核心功能,而且还提供了字符串处理这样的复杂功能。比如说,NSLinguisticTagger可以解析字符串并找到其中的全部名词、动词、代词等。

        还有一个与Foundation相伴的框架,叫CoreFoundation。虽然从技术上讲CoreFoundation不是OC框架,但她却是编写OC应用程序应该熟悉的框架。CoreFoundation与Foundation不仅名字相似,而且还有更紧密的关系。有个功能叫做“无缝桥接”(toll-free bridging),可以把CoreFoundation中的C语言数据结构平滑转为Foundation中的OC对象,也可以反向转换。比方说Foundation框架中的字符串是NSString,而它可以转化为CoreFoundation里对应的CFString对象。

        除了Foundation与CoreFoundation之外,还有很多系统库,其中包括但不限于下面列出的这些:

● CFNetwork 此框架提供了C语言级别的网络通信能力,它将“BSD套接字”抽象成易于使用的网络接口。如NSURLConnection

● CoreAudio 该框架所提供的C语言API可用来操作设备上的音频硬件。

● AVFoundation 此框架所提供的OC对象可用来回放并录制音视频,比如能在UI视图里播放视频。

● CoreData 此框架所提供的OC接口可将对象放入数据库

● CoreText 此框架提供的C语言接口可以高效执行文字排版及渲染操作。

        可以看出OC编程一项重要特点,就是:经常需要使用底层C语言级API。用C语言来实现API的好处是,可以绕过OC的运行期系统,从而提升执行速度。当然由于ARC只负责OC对象,所以使用这些API时尤其需要注意内存管理问题。

    UI框架是UIKit,它提供了Foundation与CoreFoundation之上的OC类。框架里含有UI元素,也含有粘合机制,令开发者可将所有相关内容组装为应用程序。在这些主要的UI框架下,是CoreAnimation与CoreGraphics框架。

    CoreAnimation是OC语言写的,它提供了一些渲染图形并播放动画的工具。其又是QuartzCore一部分。

    CoreGraphics 是C语言写的,其提供了2D渲染所必备的数据结构与函数。

    还有很多框架建在UI框架之上,比如MapKit提供地图功能,Social框架提供社交网络功能。

第48条:多用块枚举,少用for循环

    编程中经常需要遍历collection元素,做法有标准的for循环,OC1.0的NSEnumerator和OC2.0的fast NSEnumerator。语言引入“块”这一特性后,又多出来几种新的遍历方式。

    for循环大家很熟悉,很简单。但是遍历字典和set的时候就稍麻烦,for循环有一个优势,可以反向遍历。在删除数组中一个元素的时候采用反向遍历

    OC 1.0的NSEnumerator是个抽象基类,定义了两个方法,供具体的子类实现

-(NSArray*) allObjects;
-(id) nextObject;

    举例,遍历数字

NSArray *anArray=/*....*/;
NSEnumerator *enumerator = [anArray objectEnumerator];
id object;
while((object = [enumerator nextObject]) != nil){
//do something
}

快速遍历,就是for-in语句

直接上代码,这种办法比上面两种都高效,安全,简单,强烈推荐!在删除数组元素的时候,同样可以反序执行。

NSArray *anArray=/*...*/;
for (id object in anArray){
//do something
}
//dictionary
NSDictionary* dic = /*...*/;
for(id key in dic){
id value = dic[key];
//do something
}
//set
NSSet *aSet = /*...*/;
for (id object in aSet){
//do something
}
//反向遍历
NSArray *anArray=/*...*/;
for (id object in [anArray reverseObjectEnumerator]){
//do something
}

基于块的变量方式

    当前OC中,最新引入的一种做法句ishi基于块来遍历。这种做法比前三种效率都高,但是代码量比for-in多。

NSArray *anArray=/*...*/;
[anArray enumerateObjectUsingBlock]:
^(id object,NSUInter idx,BOOL *stop){
// do something
if(shouldStop){
*stop = yes;
}
}];
其他collection类似

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

    上面提到过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对象的所有权。

第50条:构建缓存时选用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 第51条:精简initialize 与 load的实现代码


第52条:别忘了NSTimer会保留其目标对象

    Foundation框架中有个类叫做NSTimer,开发者可以指定绝对的日期与时间,以便执行任务。

+(NSTimer) scheduledTimerWithTimeInterval: (NSTimerInterval)seconds target:(id)target selector:(SEL)selector userInfo:(id)userInfo repeats:(BOOL)repeats;

直接上代码吧

#import 
@interface EOCClass : NSObject
-(void)startPolling;
-(void)stopPolling;
@end

@implementation EOCClass{
NSTimer* _pollTimer
}
-(id) init{
return [super init];
}
-(void) dealloc{
[_pollTimer invalidate];
}
-(void) stopPolling{
[_pollTimer invalidate]:
_pollTimer = nil;
}
-(void) startPolling{
_pollTimer = [NSTimer scheduledTimerWithTimeInterval:5.0 target:self selector:@selector(p_doPoll) userInfo:nil repeats:YES];
}
-(void) p_doPoll{
//poll the resource;
}
@end

由于计时器的时候,目标对象是self,所以保留了self实例,由于计时器是用实例变量存放的,所以实例也保留了计时器。所以形成了循环引用。如果没有人调用invalidate那么这个循环引用一直存在。


    如何写一个安全的NSTimer对象,解决办法就是:实现NSTimer的分类,并将self写成weak。所以,block中合适使用weak self就看是否有循环引用。例如:

#import 
@interface NSTimer(EOCBlockSupport)
+(NSTimer*) eoc_scheduledTimerWithTimeInterval:(NSTimeInterval)interval block:(void(^)())block repeats:(BOOL)repeats;
@end
@implementation NSTimer(EOCBlockSupport)
+(NSTimer*) eoc_scheduledTimerWithTimeInterval:(NSTimeInterval)interval block:(void(^)())block repeats:(BOOL)repeats{
return [self scheduledTimerWithTimerInterval:interval target:self selector:@selector(eoc_blockInvoke:) userInfo:[block copy] repeats:repeats];
}
+(void)eoc_blockInvoke:(NSTimer*)timer{
void(^block)() = timer.userInfo;
if(block){
block();
}
}
@end
//再修改一下startPolling接口
-(void) startPolling{
__weak EOCClass *weakSelf = self;
_pollTimer = [NSTimer eoc_scheduledTimerWithTimeInterval:50 block:^
{ EOCClass *strOngSelf= weakSelf;
[strongSelf p_doPoll];
} repeats:yes];
}

这样就可以解决这个问题了.

(完)!


推荐阅读
  • 本文介绍了数据库的存储结构及其重要性,强调了关系数据库范例中将逻辑存储与物理存储分开的必要性。通过逻辑结构和物理结构的分离,可以实现对物理存储的重新组织和数据库的迁移,而应用程序不会察觉到任何更改。文章还展示了Oracle数据库的逻辑结构和物理结构,并介绍了表空间的概念和作用。 ... [详细]
  • Redis底层数据结构之压缩列表的介绍及实现原理
    本文介绍了Redis底层数据结构之压缩列表的概念、实现原理以及使用场景。压缩列表是Redis为了节约内存而开发的一种顺序数据结构,由特殊编码的连续内存块组成。文章详细解释了压缩列表的构成和各个属性的含义,以及如何通过指针来计算表尾节点的地址。压缩列表适用于列表键和哈希键中只包含少量小整数值和短字符串的情况。通过使用压缩列表,可以有效减少内存占用,提升Redis的性能。 ... [详细]
  • 本文介绍了Swing组件的用法,重点讲解了图标接口的定义和创建方法。图标接口用来将图标与各种组件相关联,可以是简单的绘画或使用磁盘上的GIF格式图像。文章详细介绍了图标接口的属性和绘制方法,并给出了一个菱形图标的实现示例。该示例可以配置图标的尺寸、颜色和填充状态。 ... [详细]
  • 在Oracle11g以前版本中的的DataGuard物理备用数据库,可以以只读的方式打开数据库,但此时MediaRecovery利用日志进行数据同步的过 ... [详细]
  • 合并列值-合并为一列问题需求:createtabletab(Aint,Bint,Cint)inserttabselect1,2,3unionallsel ... [详细]
  • 本文介绍了C#中数据集DataSet对象的使用及相关方法详解,包括DataSet对象的概述、与数据关系对象的互联、Rows集合和Columns集合的组成,以及DataSet对象常用的方法之一——Merge方法的使用。通过本文的阅读,读者可以了解到DataSet对象在C#中的重要性和使用方法。 ... [详细]
  • 计算机存储系统的层次结构及其优势
    本文介绍了计算机存储系统的层次结构,包括高速缓存、主存储器和辅助存储器三个层次。通过分层存储数据可以提高程序的执行效率。计算机存储系统的层次结构将各种不同存储容量、存取速度和价格的存储器有机组合成整体,形成可寻址存储空间比主存储器空间大得多的存储整体。由于辅助存储器容量大、价格低,使得整体存储系统的平均价格降低。同时,高速缓存的存取速度可以和CPU的工作速度相匹配,进一步提高程序执行效率。 ... [详细]
  • 本文介绍了一个在线急等问题解决方法,即如何统计数据库中某个字段下的所有数据,并将结果显示在文本框里。作者提到了自己是一个菜鸟,希望能够得到帮助。作者使用的是ACCESS数据库,并且给出了一个例子,希望得到的结果是560。作者还提到自己已经尝试了使用"select sum(字段2) from 表名"的语句,得到的结果是650,但不知道如何得到560。希望能够得到解决方案。 ... [详细]
  • 高质量SQL书写的30条建议
    本文提供了30条关于优化SQL的建议,包括避免使用select *,使用具体字段,以及使用limit 1等。这些建议是基于实际开发经验总结出来的,旨在帮助读者优化SQL查询。 ... [详细]
  • 前景:当UI一个查询条件为多项选择,或录入多个条件的时候,比如查询所有名称里面包含以下动态条件,需要模糊查询里面每一项时比如是这样一个数组条件:newstring[]{兴业银行, ... [详细]
  • 如何在php中将mysql查询结果赋值给变量
    本文介绍了在php中将mysql查询结果赋值给变量的方法,包括从mysql表中查询count(学号)并赋值给一个变量,以及如何将sql中查询单条结果赋值给php页面的一个变量。同时还讨论了php调用mysql查询结果到变量的方法,并提供了示例代码。 ... [详细]
  • Java中包装类的设计原因以及操作方法
    本文主要介绍了Java中设计包装类的原因以及操作方法。在Java中,除了对象类型,还有八大基本类型,为了将基本类型转换成对象,Java引入了包装类。文章通过介绍包装类的定义和实现,解答了为什么需要包装类的问题,并提供了简单易用的操作方法。通过本文的学习,读者可以更好地理解和应用Java中的包装类。 ... [详细]
  • 先看官方文档TheJavaTutorialshavebeenwrittenforJDK8.Examplesandpracticesdescribedinthispagedontta ... [详细]
  • 本文分析了Wince程序内存和存储内存的分布及作用。Wince内存包括系统内存、对象存储和程序内存,其中系统内存占用了一部分SDRAM,而剩下的30M为程序内存和存储内存。对象存储是嵌入式wince操作系统中的一个新概念,常用于消费电子设备中。此外,文章还介绍了主电源和后备电池在操作系统中的作用。 ... [详细]
  • DSP中cmd文件的命令文件组成及其作用
    本文介绍了DSP中cmd文件的命令文件的组成和作用,包括链接器配置文件的存放链接器配置信息、命令文件的组成、MEMORY和SECTIONS两个伪指令的使用、CMD分配ROM和RAM空间的目的以及MEMORY指定芯片的ROM和RAM大小和划分区间的方法。同时强调了根据不同芯片进行修改的必要性,以适应不同芯片的存储用户程序的需求。 ... [详细]
author-avatar
快活林2007
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有