热门标签 | 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];
}

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

(完)!


推荐阅读
  • Hadoop集群搭建:实现SSH无密码登录
    本文介绍了如何在CentOS 7 64位操作系统环境下配置Hadoop集群中的SSH无密码登录,包括环境准备、用户创建、密钥生成及配置等步骤。 ... [详细]
  • 本文介绍了一种在 Android 开发中动态修改 strings.xml 文件中字符串值的有效方法。通过使用占位符,开发者可以在运行时根据需要填充具体的值,从而提高应用的灵活性和可维护性。 ... [详细]
  • 2023年1月28日网络安全热点
    涵盖最新的网络安全动态,包括OpenSSH和WordPress的安全更新、VirtualBox提权漏洞、以及谷歌推出的新证书验证机制等内容。 ... [详细]
  • 本文由公众号【数智物语】(ID: decision_engine)发布,关注获取更多干货。文章探讨了从数据收集到清洗、建模及可视化的全过程,介绍了41款实用工具,旨在帮助数据科学家和分析师提升工作效率。 ... [详细]
  • 如何高效学习鸿蒙操作系统:开发者指南
    本文探讨了开发者如何更有效地学习鸿蒙操作系统,提供了来自行业专家的建议,包括系统化学习方法、职业规划建议以及具体的开发技巧。 ... [详细]
  • 本文探讨了如何使用Scrapy框架构建高效的数据采集系统,以及如何通过异步处理技术提升数据存储的效率。同时,文章还介绍了针对不同网站采用的不同采集策略。 ... [详细]
  • 本文介绍了如何使用 Python 的 Pyglet 库加载并显示图像。Pyglet 是一个用于开发图形用户界面应用的强大工具,特别适用于游戏和多媒体项目。 ... [详细]
  • 本文将详细介绍Fuel CMS如何基于CodeIgniter框架构建,包括其单入口模式的实现方式及关键配置文件的作用。通过分析本地环境中的index.php和.htaccess文件,我们将更好地理解Fuel CMS的核心架构。 ... [详细]
  • 视觉Transformer综述
    本文综述了视觉Transformer在计算机视觉领域的应用,从原始Transformer出发,详细介绍了其在图像分类、目标检测和图像分割等任务中的最新进展。文章不仅涵盖了基础的Transformer架构,还深入探讨了各类增强版Transformer模型的设计思路和技术细节。 ... [详细]
  • 使用R语言进行Foodmart数据的关联规则分析与可视化
    本文探讨了如何利用R语言中的arules和arulesViz包对Foodmart数据集进行关联规则的挖掘与可视化。文章首先介绍了数据集的基本情况,然后逐步展示了如何进行数据预处理、规则挖掘及结果的图形化呈现。 ... [详细]
  • 开发笔记:每篇半小时1天入门MongoDB——3.MongoDB可视化及shell详解
    开发笔记:每篇半小时1天入门MongoDB——3.MongoDB可视化及shell详解 ... [详细]
  • 本文详细探讨了编程中的命名空间与作用域概念,包括其定义、类型以及在不同上下文中的应用。 ... [详细]
  • 本文提供了一个详尽的前端开发资源列表,涵盖了从基础入门到高级应用的各个方面,包括HTML5、CSS3、JavaScript框架及库、移动开发、API接口、工具与插件等。 ... [详细]
  • Java虚拟机及其发展历程
    Java虚拟机(JVM)是每个Java开发者日常工作中不可或缺的一部分,但其背后的运作机制却往往显得神秘莫测。本文将探讨Java及其虚拟机的发展历程,帮助读者深入了解这一关键技术。 ... [详细]
  • 深入解析Unity3D游戏开发中的音频播放技术
    在游戏开发中,音频播放是提升玩家沉浸感的关键因素之一。本文将探讨如何在Unity3D中高效地管理和播放不同类型的游戏音频,包括背景音乐和效果音效,并介绍实现这些功能的具体步骤。 ... [详细]
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社区 版权所有