对于想了解Objective-C2.0withCocoaFoundation-(Helloword-1)的读者,本文将是一篇不可错过的文章,并且为您提供关于Cocoa/Objective-CShell
对于想了解Objective-C 2.0 with Cocoa Foundation - (Hello word-1)的读者,本文将是一篇不可错过的文章,并且为您提供关于Cocoa/Objective-C Shell命令行执行、collection element of type ''CGColorRef _Nullable'' (aka''stuct CGColor*'')is not an Objective-C object、Foundation Kit「Learn Objective-C on Mac、iOS7中Objective-C和Foundation的新特性(What’s New in Obj的有价值信息。
本文目录一览:- Objective-C 2.0 with Cocoa Foundation - (Hello word-1)
- Cocoa/Objective-C Shell命令行执行
- collection element of type ''CGColorRef _Nullable'' (aka''stuct CGColor*'')is not an Objective-C object
- Foundation Kit「Learn Objective-C on Mac
- iOS7中Objective-C和Foundation的新特性(What’s New in Obj
Objective-C 2.0 with Cocoa Foundation - (Hello word-1)
2.1,构筑Hello,World
第一步,启动Xcode。初次启动的时候,也许会弹出一个“Welcome to Xcode”的一个对话框。这个对话框和我们的主题没有关系,我们可以把它关掉。
第二步,选择屏幕上部菜单的“File->New Project”,出现了一个让你选择项目种类的对话框。你需要在对话框的左边选择“Command Line Utility” ,然后在右边选择“Foundation Tool”,然后选择“Choose...”按钮。如图2.1所示。
图2-1,新建项目
注意
也许有人会问,你不是要讲解iphone的开发,那么为什么不选择“iPhone OS”下面的“Application”呢?
是这样的,在这个系列当中,笔者主要侧重于objecsive-C的语法的讲解,为了使得讲解简单易懂,清除掉所有和要讲解的内容无关的东西,所以笔者在这里只是使用最简单的命令行。
第三步,Xcode会提问你项目的名字,在“Save As”里面输入“02-Hello World”,然后选择“Save”。如图2-2所示
图2-2,输入项目的名字
第四步,得到一个如图2-3所示的一个画面。尝试一下用鼠标分别点击左侧窗口栏里面的“02-Hello World”,“Source”.“Documentation”,“External Frameworks and Libraries”,“Products”,然后观察一下右边的窗口都出现了什么东西。一般来说,“02-Hello World”就是项目的名字下面是项目所有的文件的列表。项目下面的子目录分别是和这个项目相关的一些虚拟或者实际上的目录。为什么我说是虚拟的呢?大家可以通过Finder打开你的工程文件的目录,你会发现你的所有文件居然都在根目录下,根本就不存在什么“Source”之类的目录。
图2-3,项目浏览窗口
第五步,选择屏幕上方菜单的“Run”然后选择“Console”,出现了如图2-4所示的画面,用鼠标点击窗口中间的“Build and Go”按钮。
图2-4,运行结果画面
如果不出什么意外的话,大家应该看到我们熟悉得不能再熟悉的“Hello Wolrd!” 。由于我们没有写任何的代码,所以从理论上来说,这部分代码不应该出现编译错误。好的,从下面开始,笔者要开始对这个Hello World里面的一些新鲜的东西进行讲解。
Cocoa/Objective-C Shell命令行执行
我有命令作为字符串“命令”,但可以根据需要轻松地操作数据。
没有必要获得返回的输出值。
解决方法
Nsstring *path = @"/path/to/executable"; NSArray *args = [NSArray arrayWithObjects:...,nil]; [[NSTask launchedTaskWithLaunchPath:path arguments:args] waitUntilExit];
-waitUntilExit调用确保在继续之前完成。如果任务可以是异步的,你可以删除该调用,并让NSTask做到这一点。
collection element of type ''CGColorRef _Nullable'' (aka''stuct CGColor*'')is not an Objective-C object
类型转换为ID解决问题: “Collection element of type ''CGColorRef'' (aka ''struct CGColor *'') is not an Objective-C object”
编译器理解Objective-C方法返回的核心基础类型遵循历史可命名约定(见-高级内存管理编程指南)。例如,编译器知道,在iOS的cgcolor返回用UIColor的cgcolor方法不拥有。您必须仍然使用一个合适的类型转换,
1down voteaccepted |
It is documented in the "Transitioning to ARC Release Notes":
|
参考:http://stackoverflow.com/questions/21933209/why-type-cast-to-id-will-get-rid-of-this-error-message-collection-element-of-ty
Foundation Kit「Learn Objective-C on Mac
Cocoa
Cocoa框架實際上由Foundation Kit和AppKit兩個不同的框架組成.Foundation框架中有很多有用的,面向數據的低級類和數據類型.此框架主要用來處理界面無關的內容,AppKit則包含了所有的用戶接口對象和高級類.
結構體類型
Cocoa中一些類據類型是使用struct實現的,不使用對象實現的原因就在於性能.對象的開銷比較大(對象都是動態分配的).所以對這種數據類型可以使用三種方式賦值.
typedef struct _NSRange{
unsigned int location;
unsigned int length;
}NSRange;
1.
NSRange range;
range.lcation = 17;
range.length = 4;
2.
NSRange range = (17,4);
3.
NSRage range = NSMakeTange(17,4);
其他還有NSPoint,NSSize,NSRect等數據類型也是如此,除了1,2種賦值方法外,也都有對應的函數可以生成數據:NSMakePoint(),NSMakeSize(),NSMakeRect()等.
Nsstring
@""是Nsstring字面量寫法.
Nsstring可以准確地處理Unicode字符串.
+ stringWithFormat: 類級方法,通過格式化字符串和一組參數輸出格式化後的結果.
– isEqualToString: 對象級方法,比較與所給的字符串是否相同.
Cocoa中的字符串是對象,所以不能用 == 號來比較.如果使用 == 號比較兩個字符串對象,那麼事實上是比較了兩個對象的指針.
– compare:與給定的字符串比較(區分大小寫),返回一個枚舉值作為結果.
– compare:options:
– compare:options:range:
– compare:options:range:locale:字符串比較方法,帶選項的版本(如:是否區分大小寫)
– hasPrefix:測試是否以給定的字符串開頭
– hasSuffix:測試是否以給定的字符串結尾
– rangeOfString:查詢給定字符串在字符串對象中的位置.
NSMutableString
Nsstring的子類, NSMutableString是Nsstring的可修改版本.
+ stringWithCapacity:容量建議值.對象會以此方法給出的建議值劃分出一塊內存作為可變字符串對象的初始大小.合理使用可以提高性能.
– appendFormat:向字符串對象追加內容.
– appendString:使用格式化方式向字符串對象追加內容.
– deleteCharactersInRange:從字符串對象的指定范圍中刪除字符串.
集合
NSArray
NSArrary是一個用來存儲對象的有序列表.
限制:只能存儲Objective-C對象.不能存儲C語言中的基本數據類型(如int,float,enum,struct,或者NSArray中的隨機指針),也不能存儲nil或者NULL值.
– count 獲得列表包含的對象數.
– objectAtIndex:獲取特定索引處的對象.索引值超出范圍時,將引發一個異常.
Cocoa框架中對象往往都是以類族的形式實現的.如:NSArray對象可能會在運行時發現其實運作的是NSCFArray(來自Core Foundation框架(C語言的實現版本),很多Cocoa對象都是如此做橋接的).
NSMutableArray
NSArray的可變版本.
+ arrayWithCapacity:以建議值作為初始化大小.
– addobject:追加對象
– removeObjectAtIndex:從指定索引處刪除對象
NSEnumerator
遍歷集合時:
使用for循環向集合對象發送objectAtIndex:消息來獲取對象.
使用枚舉對象來完成遍歷集合的工作.
Mac OS X Tiger 之前的系統,支持的語法:
NSEnumerator *enumerator;
enumerator = [array objectEnumerator];
id thingie;
while(thingie = [enumerator nextObject]){
//something to do.
}
即向集合對象發送objectEnumerator消息,以獲取一個枚舉對象(或者NSEnumerator類或其子類的實例),然後在while循環中向此枚舉對象循環發送nextObject以依次獲取枚舉中的每個對象,直到枚舉的末尾(直到nextObject消息返回一個nil對象).
Mac OS X Leopard之後的系統可使用如下語法:
for (Nsstring *string in array){
//to do something.
}
NSDictionary / NSMutableDictionary
字典對象(及可變型字典對象).
+ dictionaryWithObjectsAndKeys:使用所給的鍵值對建立字典.
– setobject:forKey:添加字典項
– removeObjectForKey:刪除字典項
不要擴展Cocoa框架下的類
Cocoa中許多類都是以類簇的方式實現的.即它們是一群隱藏在通用接口下的與實現相關的類.
比如:使用Nsstring對象的是個,實際上獲得的可能是NSLiteralString,NSCFString,NSSimpleCString,NSBallofString或者其他未寫入文檔的與實現相關的對象.
不要想著為以類簇方式實現的類添加子類,這可能是很痛苦的事情,想要擴展這類類的能力時,可考慮"復合"或者"類別".
數值類
NSNumber
用於包裝基本數據類型,如:int,float等.成為一個對象,以便將基本數據類型放入集合類中.
+ numberWithBool:由布爾型生成對象
+ numberWithChar:字符型
+ numberWithDouble:雙精度浮點型
+ numberWithFloat:單精度浮點型
+ numberWithInt:整型
+ numberWithInteger:ObjC整型
+ numberWithLong:長整型
+ numberWithLongLong:長長整型
+ numberWithShort:短整型
使用以下方法可以從對象中提取回基本數據型值.
– boolValue
– charValue
– decimalValue
– doubleValue
– floatValue
– intValue
– integerValue
– longLongValue
– longValue
– shortValue
都是顧名思義的方法名.
NSValue
NSValue是NSNumber的父類,可以用來包裝任意值.NSNumber不能包裝的struct,也可以用這個類來包裝.
+ valueWithBytes:objCType:第一參數傳入要包裝的數值的地址.第二個參數為數據類型的描述字符串(一般可以直接用@encode命令來生成)
NSRect rect = NSMakeRect(1,2,30,40);
NSValue *value = [NSValue valueWithBytes:&rect objCType:@encode(NSRect)];
[array addobject:value];
使用- getValue:方法可以從NSValue對象中提取出數據的指針(可以看到get前輟的方法約定,總是用來提取指針,而不是值).
NSValue中有一些方法,可以用來快速包裝Cocoa常用結構體數據類型:
+ valueWithPoint:快速包裝NSPoint對象
+ valueWithRange:NSRange
+ valueWithRect:NSRect
+ valueWithSize:NSSize
NSNull
空類型,由於集合類中不能添加nil值(被用來識別為集合的結尾處),所以你可以使用NSNull對象添加到集合中,以表示空(無,沒有)成員.
iOS7中Objective-C和Foundation的新特性(What’s New in Obj
说明
注意事项(Ray):文章来自iOS 7 by Tutorials iOS 7Feast的一部分(略)
Objective-C 是最重要的iOS和OSX apps的开发工具。你可以使用其他语言的第三方框架开发apps,例如HTML&Javascript或者C#,但是如果你很快的写出一个超炫的高效率的原声apps你就需要使Objective-C。
Foundation 是你开发Objective-C应用时用到的核心框架之一。
作为一名iOS开发者,非常有必要了解最新的Objective-C和Foundation的特性,在iOS7中有了一些重要的改变需要你了解。
在这篇文章中,你将快速浏览一些在Objective-C和Foundation中新的功能。
1.Modules(模块)
机会是好的,你已经写了一千遍或更多#import语句:
[cpp] view plaincopy
#import <UIKit/UIKit.h>
#import <MapKit/MapKit.h>
#import <iAd/iAd.h>
这个语法要追溯到Objective-C的根:vanilla C。#import语句是预处理器指令和#include有类似的方式工作。唯一的区别是#import不会导入已经导入的头文件;它是一次性处理。
当预处理遇到一个#import命令时,就会按字面的意思用被导入的头文件的全部内容替换那一行。预编译会递归的这么处理,即使可能是大量的头文件。
UIKit的头文件,UIKit.h,包含了UIKit框架中包含的所有其他头文件。这意味着,您不必手动导入每个框架的头文件,例如UIViewController.h,UIView.h UIButton.h的。
对UIKit框架的大小感到好奇嘛?通过计算所有行的全部UIKit中的头,你会发现它相当于超过11,000行代码!
在一个标准的iOS应用,你会在您的大部分文件中导入的UIKit,这意味着每一个文件最终被长11000行。这是不够理想的,更多的代码意味着更长的编译时间。
1.1 原始解决方案:预编译头文件(Original solution: Pre-compiled Headers)
预编译的头文件,或PCH文件,试图解决这个问题,通过提供在编译的预处理阶段预先计算和缓存需要的代码。你可能看过Xcode生成的stock PCH 文件,像下面这样:
[cpp] view plaincopy
#import <Availability.h>
#ifndef __IPHONE_5_0
#warning "This project uses features only available in iOS SDK 5.0 and later."
#endif
#ifdef __OBJC__
#import <UIKit/UIKit.h>
#import <Foundation/Foundation.h>
#endif
如果开发人员开发的app的targets是iOS5之前的一个SDK,#warning将通知他们。UIKit和Foundation umbrella 头文件是stockPCH的一部分。因为在您的应用程序里的每一个文件将使用Foundation并且大部分会使用UIKit。因此这些都是很好的添加对 于PCH文件以便于在你的APP中预先计算和缓存这些文件的编译文件。
你可能会问“这有什么问题嘛?”PCH没有任何技术性的问题就像是——if it isn’t broke, don’tfix it(没有坏,就不要修)。然而你可能错失了很多性能优势,由于一个易维护的、高度优化的PCH文件导致(你可能会错过了一台主机上的维护良好的,高度优 化的PCH文件的性能优势)。例如你可能在好几个地方用到Map Kit框架,你就会看到了通过添加Map Kit umbrella头文件或者单独的你用到的Map Kit类头文件到PCH文件中对编译时间的提升。
我们都是lazy developers ,没有人有时间去维护我们工作的项目的PCH文件。那就是为什么modules被开发为LLVM的特性。
注意事项:LLVM是一个模块化和可重复使用的编译器和工具技术与Xcode捆绑的集合。 LLVM有几个组成部分:对oc开发者最重要的是clang,原生的C、C++和Objective-C编译器;和LLDB,原生debugger—开发者最好的朋友。
1.2 新的解决方案:模块 (Modules)
Modules第一次在Objective-C中公共露面是在2012 LLVM开发者大会上Apple’s Doug Gregor的一次谈话。这是一次迷人的谈话,强烈推荐给对编译感兴趣的人。你可以在线看这些视频http://llvm.org/devmtg/2012-11/#talk6。
Modules封装框架比以往任何时候更加清洁。不再需要预处理逐行地用文件所有内容替换#import指令。相反,一个模块包含了一个框架到自包含的块 中,就像PCH文件预编译的方式一样提升了编译速度。并且你不需要在PCH文件中声明你要用到哪些框架,使用Modules简单的获得了速度上的提升。
但是Modules不只有这些,我相信你会想起这些步骤当你第一次在一个app使用一个新的框架的时候,就像下面这样:
1. 在使用框架的文件中添加#import
2. 用用的框架写代码
3. 编译
4. 查看链接错误
5. 想起忘记链接的框架
6. 添加忘记的框架到项目中
7. 重新编译
忘记链接框架式是一件经常的犯的错误,但是Modules解决的非常好。
一个Modules不仅告诉编译器哪些头文件组成了Modules,而且还告诉编译器什么需要链接。这个就解救了你不用你去手动的链接框架。这虽然是一件小事,但是能让开发更加简单就是一件好事。
1.3 怎样使用Modules
Modules的使用相当简单。对于存在的工程,第一件事情就是使这个功能生效。你可以在项目的Build Settings通过搜索Modules找到这个选项,改变Enable Modules 选项为YES,像这样:
所有的新工程都是默认开启这个功能的,但是你应该在你所有存在的工程内都开启这个功能。
Link Frameworks Automatically选项可以用来开启或者关闭自动连接框架的功能,就像描述的那么简单。还是有一点原因的为什么你会想要关闭这个功能。
一旦Modules功能开启,你就可以在你的代码中使用它了。像这样做,对以前用到的语法有一点小小的改动。用@import代替#import:
[cpp] view plaincopy
@import UIKit;
@import MapKit;
@import iAd;
只导入一个框架中你需要的部分也是可能的。例如你只想要导入UIView,你就这样写:
[cpp] view plaincopy
@import UIKit.UIView;
对的-他真的是这么简单,技术上,你不需要把所有的#import都换成@import ,因为编译器会隐式的转换他们。然而尽可能的用新的语法还是好的习惯。
在你兴奋的要开始使用Modules之前,不幸的是有一个小警告。Xcode5的Modules还不支持你自己的或者第三方的框架。这是一个不幸的缺点,没有事情是完美的,即使是Objective-C!
2.新的返回类型-instancetype
Objective-C添加了一个新的返回类型,名字叫instancetype。这个仅仅被用作Objective-C方法的返回类型和对编译器的一个暗示,暗示方法的返回类型将是这个方法属于的类的实例。
注意事项: 这个特征在iOS7和Xcode上没有严格,但是随着时间的推移会被悄悄的加进最近的Clang。然而Xcode5第一次声明苹果已经在他们的框架中使用了这个。你可以再官方的Clang网页看到更多的内容:http://clang.llvm.org/docs/LanguageExtensions.html#objective-c-features
为什么要使用instancetype呢?看看下面的代码:
[cpp] view plaincopy
NSDictionary *d = [NSArray arrayWithObjects:@(1), @(2), nil];
NSLog(@"%i", d.count);
虽然这个明显是不正确的,但是编译器却不会提醒你任何错误。自己尝试一下在Xcode4.6下编译。你将看到没有任何警告,但是这段代码明显是错误的。这段代码甚至能够没有异常的跑起来,因为NSDictory和NSArray的实例都能相应count。
这段代码正常的原因是由于Objective-C的强大的动态特性。这个类型是对编译器的一个指导。Count方法在运行的时候被查找无论什么类,正好 dictionary变量有这个方法。在这种情况下,count方法存在,编译器相信他是正确的。然而稍后你用到了NSDictionary有而 NSArray没有的方法例如objectAtIndex:就会出现问题。首先他不会明确指出问题出现在哪里。
但是问什么编译器没有指出 +[NSArray arrayWithObjects:]方法返回的实例不是NSDictionary实例呢?那是因为这个方法声明如下:
[cpp] view plaincopy
+ (id)arrayWithObjects:(id)firstObj, ...;
注意到返回类型是id。id类型是一个意味着任何Objective-C类的umbrella类型。他甚至都不是NSObject的子类。方法没有返回类 型信息而不是返回Objective-C类的实例。这样做是有用的,当你隐式的转换id到一个确切的类型时编译器不会警告你。例如上面的 NSDictionary例子。如果产生警告,id就没有用啦。
但是这个方法的返回类型为什么是id呢?你可以子类化这个方法然后仍然没有问题的使用它。为了证明为什么,考虑下面的NSArray的子类:
[cpp] view plaincopy
@interface MyArray : NSArray
@end
现在考虑下你的子类在下面的代码的使用:
[html] view plaincopy
MyArray *array = [MyArray arrayWithObjects:@(1), @(2), nil];
现在你应该知道为什么arrayWithObjects:返回类型必须是id。如果是NSArray*,这个子类需要转化成必要的类。这就是新的 instancetype返回类型用到的地方。如果你看iOS7SDK中NSArray的头文件,你将注意到这个方法变成了下面的样子:
[cpp] view plaincopy
+ (instancetype)arrayWithObjects:(id)firstObj, ...;
唯一的不同就是返回类型。新的返回类型提示编译器返回类型是方法被调用的类的实例。所以当arrayWithObjects:被调用的是NSArray时,返回类型是NSArray*。当调用的是MyArray时,返回类型是MyArray*。
当维护成功子类化的能力的时候,用id就会出现的问题。如果用Xcode5编译原始的代码,你会看到下面的警告:
[cpp] view plaincopy
warning: incompatible pointer types initializing ''NSDictionary *'' with an expression of type ''NSArray *'' [-Wincompatible-pointer-types]
NSDictionary *d = [NSArray arrayWithObjects:@(1), @(2), nil];
那是有帮助的,现在你有机会修改这个问题以防止接下来crash。
初始化方法是候选要使用这个新的返回类型的。现在如果你设置初始化方法返回一个不完整的类型编译器已经提醒你了。但是他可能隐式的转化id到instancetype。你应该仍然使用instancetype,因为明确一点还是比较好的。
尽可能多的使用instancetype,他会成为Apple的标准-你不会知道这个将减少你多少你将来的degugging的痛苦时间。
3.新的 Foundations
接下来就是Objective-C核心开发框架Foundation的一些新东西。没有Foundation很难开发Objective-C应用,所有的iOS Apps都需要使用。在新的iOS SDK中看看这些新添加的内容。
Foundation最主要的提升是网络。(说的应该是NSURLSession)在iOS 7 by Tutorials 有一整章描述。(略)
文章剩下部分展示了Foundation新增加的和改变的东西。
3.1 NSArray
尝试在NSArray实例中访问一个Object,如果下表越界将爆出异常。当你用数组当做队列的时候,你可能经常要访问数组中第一个或者最后一个元素。 在先进先出队列(FIFO)你可能要从数组的前端POP元素,如果是先进后出队列(FILO)就要从数组末尾POP元素。
然而,当你访问数组的第一个或者最后一个元素的时候,你一定要确定没有超出数组的边界,如果数组是空得话经常发生这样的访问。这就会导致在调用objectAtIndex:不报错而产生冗余的代码,就像下面的这样:
[cpp] view plaincopy
NSMutableArray *queue = [NSMutableArray new];
// ...
if (queue.count > 0) {
id firstObject = [queue objectAtIndex:0];
// Use firstObject
}
// ...
if (queue.count > 0) {
id lastObject = [queue objectAtIndex:(queue.count - 1)];
// Use lastObject
}
要访问最后一个元素,你应该会用到NSArray的这个方法:
[cpp] view plaincopy
- (id)lastObject;
Objective-C开发者应该可以高兴了,现在他们有了一个方法来访问数组的第一个元素:
[cpp] view plaincopy
- (id)firstObject;
简单的方法总是被证明是有用的。你不在需要检查数组是不是空的啦。你可能曾经遇到过由于越界产生的Crash。你可以看看下面的注意事项:
注意事项:如果你仔细的看NSArray头文件,其 实firstObject在iOS4.0就已经出现啦,直到iOS7才对外开放。因此你可以在iOS7之前获取这个方法,但是你必须在你自己的头文件里声 明这个方法firstObject来告诉编译器它确实存在。这不是一个提倡的方法,好歹Apple把这个方法公开了。
先前的代码可以用这两个方法重写,就不用检查数组长度了,如下:
[cpp] view plaincopy
NSMutableArray *queue = [NSMutableArray new];
// ...
id firstObject = [queue firstObject];
// Use firstObject
id lastObject = [queue lastObject];
// Use lastObject
3.2 NSData
Data是你编程处理最多的事情。NSData是Foundation类,封装了原始字节并提供方法操纵这些字节,可以从一个文件读或者写数据。但是一个简单的任务Base64编码和解码还没有原生的实现。直到iOS7才出现。
Base64是一组二进制到文本转换的方案,以ASCII格式提供二进制数据。这些方案用来编码二进制数据以存储或者通过把多媒体文件转换成文本数据进行 传输。这个能保证数据在传输过程中的完整性。Base64编码的最常见的用途是处理电子邮件附件,或者编码小图片,这些小图片是通过基于Web的API返 回的JSON相应的一部分。
在iOS7之前,Base64的 编码和解码是需要自己实现的或者使用第三方库。典型的Apple风格,现在是非常容易的使用这个功能。有四个Base64方法如下:
[cpp] view plaincopy
- (id)initWithBase64EncodedString:(NSString *)base64String
options:(NSDataBase64DecodingOptions)options;
- (NSString *)base64EncodedStringWithOptions:
(NSDataBase64EncodingOptions)options;
- (id)initWithBase64EncodedData:(NSData *)base64Data
options:(NSDataBase64DecodingOptions)options;
- (NSData *)base64EncodedDataWithOptions:
(NSDataBase64EncodingOptions)options;
头两个方法是处理字符串的,后两个方法是处理UTF-8编码数据的。这两个成对的方法功能是一样的,但是有时候用其中一个比另一个效率要高。如果你想要 Base64编码字符串然后写进文件,你应该使用UTF-8编码数据的这对方法。另一方面,如果你打算Base64编码字符串然后用做JSON,你应该使 用另外一对方法。如果你曾经实现过Base64编码方法,现在可以删除了,因为Apple已经帮你实现了。
3.3 NSTimer
NSTimers在apps中经常用来执行周期性任务。NSTimer虽然很有用但是也会产生问题。当有几个定时器在用的时候,他们可能间断性的触发。 这就是意味着CPU是间断性处于活动状态的。这样做是更加有效率的,当CPU换起的时候执行一些任务,然后进入睡眠状态。为了解决这个问题,Apple给 NSTimer添加了一个容忍属性来适应这种行为。
容忍提供系统一个指导在timer在计划之后允许延迟多长时间。为了减少CPU负荷底层系统将要集合这些活动。新属性的方法是:
[cpp] view plaincopy
- (NSTimeInterval)tolerance;
- (void)setTolerance:(NSTimeInterval)tolerance;
你可能永远都不需要用到这个属性,但是当你在非常密切相近的触发了几个定时器,你可能发现他是有用的,当你在用Instruments检测CPU使用率的时候。
3.3 NSProgress
不经常见到Foundation会完整的添加一个新类。他是一个稳定的框架。主要是因为不经常用到核心的类。然而iOS7提供了一个完整的新类NSProgress。
本质上,NSProgress是用来通过Objective-C代码产生进度报告的,分离每一个独立模块的进度。例如,你可以在一些数据上执行几个不同的任务,然后每个任务可以管理他自己的进度然后报告给他的父任务。
3.3.1NSProgress结构
NSProgress最简单的使用方法是报告一些任务集合的进度。例如,你有10个任务执行,当每个任务完成的时候你可以报告进度。当有一个任务完成的时 候进度增加%10。然后在NSProgress的实例上使用Key Value Observing(KVO),你能够了解到这个实例的进度。你可以使用这个通知来更新进度条或者显示一个指示文字。
NSProgress有更多的用途。Apple通过这个父子类的关系结构使他更加强大。NSProgress的结构更像是网状树。每一个 NSProgress有一个父类和多个子类。每一个实例有一个执行的工作单元的总数,当前任务会处理完成的子任务数的更新来反馈当前状态。这么做的话,父 类也会被通知进度。
为了减少NSProgress实例的传递,每个线程有自己的NSProgress实例然后子实例可以直接从这个实例创建。没有这个功能,每个想要报告进度的任务不得不通过参数的方式来通知。
3.3.2报告进度
NSProgress使用非常简单。以下面的方法开始:
[cpp] view plaincopy
+(NSProgress *)progressWithTotalUnitCount:(int64_t)unitCount;
这个方法创建了一个NSProgress实例作为当前实例的子类,以要执行的任务单元总数来初始化。例如,如果任务是循环一个数组,然后你可能用数组数来初始化NSProgress实例。例如:
[cpp] view plaincopy
NSArray*array = /* ... */;
NSProgress*progress =
[NSProgressprogressWithTotalUnitCount:array.count];
[arrayenumerateObjectsUsingBlock:
^(id obj, NSUInteger idx, BOOL *stop) {
// Perform an expensive operation onobj
progress.completedUnitCount = idx;
}];
随着迭代的进行,上面的代码会更新NSProgress实例来反映当前进度。
3.3.3接收进度更新
你可以通过下面的属性在任何时候获取任务进度:
[cpp] view plaincopy
@property(readonly) double fractionCompleted;
返回值是0到1,显示了任务的整体进度。当没有子实例的话,fractionCompleted就是简单的完成任务数除以总得任务数。
Key Value Observing(KVO)是最好的方法来获取fractionCompleted值得变化。这么做非常简单。你只需要做的是添加一个NSProgress的fractionCompleted属性的观察者。像下面这样:
[cpp] view plaincopy
[_progressaddObserver:self
forKeyPath:@"fractionCompleted"
options:NSKeyValueObservingOptionNew
context:NULL];
然后覆盖KVO的这个方法来获取改变:
[cpp] view plaincopy
-(void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary*)change
context:(void *)context
{
if (object == _progress) {
// Handle new fractionCompleted value
return;
}
// Always call super, incase it uses KVOalso
[super observeValueForKeyPath:keyPath
ofObject:object
change:change
context:context];
}
在这个方法中你可以获取fractionCompleted的值的改变。例如你可能改变进度条或者提示文字。
当然,当你处理完的时候记得注销KVO是很重要的。
[cpp] view plaincopy
[_progressremoveObserver:self
forKeyPath:@"fractionCompleted"
context:NULL];
你必须总是要注销的,如果你没有注销,当被注册的Object释放的时候就会Crash。所以如果必要的话在dealloc中注销作为最后的保障。
关于Objective-C 2.0 with Cocoa Foundation - (Hello word-1)的介绍现已完结,谢谢您的耐心阅读,如果想了解更多关于Cocoa/Objective-C Shell命令行执行、collection element of type ''CGColorRef _Nullable'' (aka''stuct CGColor*'')is not an Objective-C object、Foundation Kit「Learn Objective-C on Mac、iOS7中Objective-C和Foundation的新特性(What’s New in Obj的相关知识,请在本站寻找。
本文标签: