Look for any podcast host, guest or anyone
Showing episodes and shows of

Mattt Thompson

Shows

Swift Package Indexing2025-08-2844 minSee Jurassic Right with Steven Ray Morris2023-10-1016 minSwift Unwrapped2020-08-0335 minCacaoCast2018-08-311h 02iOSDevLog
iOSDevLog402. nshipster-NSExpressionhttp://nshipster.cn/nsexpression/NSExpressionMattt Thompson撰写、 Zihan Xu翻译、 发布于2013年7月8日每当涉及查询或者整理信息时,Cocoa总是其他标准库羡慕的对象。通过使用NSPredicate,NSSortDescriptor,以及偶尔使用NSFetchRequest,即使是最复杂的数据任务也可以被简化成为几行极其容易读懂的代码。现在,NSHipster们无疑已经熟悉NSPredicate 了(如果你还不熟悉,下周一定要过来看看),不过如果我们更进一步看看NSPredicate,我们会发现NSPredicate其实是由更小的部分而组成:两个NSExpression(一个左手值和一个右手值),和一个运算符相比较(比如 1这并不是Wolfram Alpha,但是如果加入评估数学表达式对于你的应用很有用的话,那么...你就可以使用NSExpression。函数我们仅仅触及了NSExpression的表面。觉得一台电脑仅仅做小学数学不怎么厉害?那高中的统计学怎么样?Objective-CNSArray *numbers = @[@1, @2, @3, @4, @4, @5, @9, @11];NSExpression *expression = [NSExpression expressionForFunction:@"stddev:" arguments:@[[NSExpression expressionForConstantValue:numbers]]];id value = [expression expressionValueWithObject:nil context:nil]; // => 3.21859...NSExpression 函数以给定数目的子表达式作为参数。比如,在上述例子中,要得到集合的标准差,数列中的数字要被+expressionForConstantValue:封装。虽然只是一个小小的不便(它最终却能使得NSExpression变得极其灵活),却足以使第一次尝试它的人绊倒。如果你觉得 键值编码简单集合运算符 (@avg,@sum等等)不够用,也许NSExpression的自带的统计,算术和位运算功能能激起你的兴趣。要注意的是:根据Apple的NSExpression文档中的表格,很明显,OS X & iOS的功能可用性之间没有重叠。看起来最近的iOS版本的确支持如stddev之类的函数,但这些变化并没有显示在头文件或者文档里。如果你注意到任何变化,请以pull request的形式告诉我,不胜感激。统计average:sum:count:min:max:median:mode:stddev:基本运算这些函数需要用两个NSExpression对象来表达数字。add:to:from:subtract:multiply:by:divide:by:modulus:by:abs:高级运算sqrt:log:ln:raise:toPower:exp:边界函数ceiling: - (不小于数组中的值的最小积分值)trunc: - (最接近但不大于数组中的值的积分值)与math.h函数类似的函数ceiling非常容易和ceil(3)混淆。ceiling作用于数字数组,而ceil(3)作用于一个double值(且它并没对应的内置NSExpression函数)。floor:在这里的作用和floor(3)一样。floor:随机函数两个变量--一个带参数,一个不带参数。不带参数时,random返回rand(3)的等值,而random:则从NSExpression的数字数组中取任意元素。randomrandom:二进制运算bitwiseAnd:with:bitwiseOr:with:bitwiseXor:with:leftshift:by:rightshift:by:onesComplement:日期函数now字符串函数lowercase:uppercase:空操作noindex:自定义函数除了这些内置的函数,你也可以在NSExpression中调用自定义函数。由Dave DeLong所撰写的这篇文章 详述了这个过程。首先,在类别中定义一个对应的函数:Objective-C@interface NSNumber (Factorial)- (NSNumber *)factorial;@end@implementation NSNumber (Factorial)- (NSNumber *)factorial { return @(tgamma([self doubleValue] + 1));}@end
2016-03-1307 miniOSDevLog
iOSDevLog401. nshipster-NSDate​Components​http://nshipster.cn/nsdatecomponents/NSDate​ComponentsMattt Thompson撰写、 Candyan翻译、 发布于2012年7月31日NSDateComponents 类在Foundation的日期和时间API中扮演着重要的角色。其本身并没有什么令人印象深刻的特征,仅仅是一个日期信息的容器(信息包括:月,年,月中的某天,年中的某周,或者是否是闰月)。然而,值得一提的是,在其结合 NSCalendar和NSDateComponents 类之后,日历格式的转换变得十分方便。日期代表了时间中的某个特定时刻,而日期组件的表示则依赖于其所使用的日历系统。很多时候,这个表示形式会和我们大多数人使用的Gregorian Calendar有着很大的不同。例如Islamic Calendar一年有354或者355天,而Buddhist calendar一年会有354,355,384或者385天。从日期中提取日期组件NSDateComponents类能够被手动初始化,但是在大多数时候,会使用NSCalendar -components:fromDate:来提取某个日期的日期组件。Objective-CNSCalendar *calendar = [NSCalendar currentCalendar];NSDate *date = [NSDate date];[calendar components:(NSDayCalendarUnit | NSMonthCalendarUnit) fromDate:date];其中components参数是一个用来获取日期组件值的掩码(bitmask),有下面这些值可以选择:NSEraCalendarUnitNSYearCalendarUnitNSMonthCalendarUnitNSDayCalendarUnitNSHourCalendarUnitNSMinuteCalendarUnitNSSecondCalendarUnitNSWeekCalendarUnitNSWeekdayCalendarUnitNSWeekdayOrdinalCalendarUnitNSQuarterCalendarUnitNSWeekOfMonthCalendarUnitNSWeekOfYearCalendarUnitNSYearForWeekOfYearCalendarUnitNSCalendarCalendarUnitNSTimeZoneCalendarUnit由于其计算所有可能值的开销很大,所以随后的计算只使用指定的值(用|来分割两个不同的值,使用位运算“或”操作)。计算相对日期NSDateComponents对象可以用来计算相对日期。使用 NSCalendar -dateByAddingComponents:toDate:options:方法来确定昨天,下周或者5小时30分钟之后的日期。Objective-CNSCalendar *calendar = [NSCalendar currentCalendar];NSDate *date = [NSDate date];NSDateComponents *components = [[NSDateComponents alloc] init];[components setWeek:1];[components setHour:12];NSLog(@"1 week and twelve hours from now: %@", [calendar dateByAddingComponents:components toDate:date options:0]);用Components来创建日期NSDateComponents类最强大的特性也许就是能够通过组件反向创建NSDate对象。NSCalendar -dateFromComponents:就是用来实现这个目的的:Objective-CNSCalendar *calendar = [NSCalendar currentCalendar];NSDateComponents *components = [[NSDateComponents alloc] init];[components setYear:1987];[components setMonth:3];[compon...
2016-03-1304 miniOSDevLog
iOSDevLog399. nshipster-​NSCoding : NSKeyed​Archiverhttp://nshipster.cn/nscoding/NSCoding / NSKeyed​ArchiverMattt Thompson撰写、 Yu Jin翻译、 发布于2013年5月13日在构建应用程序时,一个重要的架构决策问题是在每次启动之间如何持久化数据。问题是如何精准的重现最后一次关闭应用前的状态;如何描述对象图以使下次完美地重新构建。在 iOS 和 OS X 上, 苹果提供了两种选择 :Core Data 或 NSKeyedArchiver / NSKeyedUnarchiver (用来将遵循 的类序列化)或者更确切地说:有三种选择,如果你算上NSURLCache的话. 在client-server应用场景下,在每次启动时加载必要的数据是一种可行的设计,尤其是结合磁盘缓存,存储服务器的响应,这样当发送对应请求的时候可以立即返回。在实践中,网络层和对象层上的缓存结合是可取的。当涉及到建模,查询,遍历,持久化复杂的对象图,那Core Data是无可代替的。Core Data 是把大锤子,但不是所有的问题都是足够大的钉子。Core Data 和 NSKeyedArchiver客观和常见的比较可能是这样的:Core Data NSKeyedArchiverEntity Modeling Yes NoQuerying Yes NoSpeed Fast SlowSerialization Format SQLite, XML, or NSData NSDataMigrations Automatic ManualUndo Manager Automatic Manual等等。在这场对决中,没有什么可比性,它看起来是一边倒的局势。...也就是说,直到你从一个稍微不同的角度看它:Core Data NSKeyedArchiverPersists State Yes YesPain in the Ass Yes No通过这些对比,在某些情况下NSKeyedArchiver是一个完全合理的选择。并非所有的应用程序需要查询的数据。并非所有的应用程序需要自动迁移。并非所有的应用程序处理大型或复杂的对象图。而且应用中确实是有一些模块更好地被一个简单的方案解决。这篇文章将关注如何,何时,为什么选择NSKeyedArchiver 和 NSCoding。希望能提供给亲爱的读者们以启发选择最合适的工具。NSCoding 是一个简单的协议,有两个方法: -initWithCoder: 和 encodeWithCoder:。遵循NSCoding协议的类可以被序列化和反序列化,这样可以归档到磁盘上或分发到网络上。举个例子:Objective-C@interface Book : NSObject @property NSString *title;@property NSString *author;@property NSUInteger pageCount;@property NSSet *categories;@property (getter = isAvailable) BOOL available;@end@implementation Book#pragma mark - NSCoding- (id)initWithCoder:(NSCoder *)decoder { self = [super init]; if (!self) { return nil; } self.title = [decoder decodeObjectForKey:@"title"]; self.author = [decoder decodeObjectForKey:@"author"]; self.pageCount = [decoder decodeIntegerForKey:@"pageCount"]; self.categories = [decoder decodeObjectForKey:@"categories"]; self.available = [decoder decodeBoolForKey:@"available"]; return self;}...
2016-03-1307 miniOSDevLog
iOSDevLog398. nshipster-NSCharacter​Sethttp://nshipster.cn/nscharacterset/NSCharacter​SetMattt Thompson撰写、 Ricky Tan翻译、 发布于2012年9月17日正如之前提前过的,基础类库(Foundation)拥有最好的、功能也最全的string类的实现。但是仅当程序员熟练掌握它时,一个string的实现才是真的好。所以本周,我们将浏览一些基础类库的string生态系统中经常用到且用错的重要组成部分:NSCharacterSet。如果你对什么是字符编码搞不清楚的话(即使你有很好的专业知识),那么你应该抓住这次机会反复阅读Joel Spolsky的这篇经典的文章"The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets (No Excuses!)"。在头脑中保持新鲜感将对你理解我们将要探讨的话题非常有帮助。NSCharacterSet ,以及它的可变版本NSMutableCharacterSet,用面向对象的方式来表示一组Unicode字符。它经常与NSString及NSScanner组合起来使用,在不同的字符上做过滤、删除或者分割操作。为了给你提供这些字符是哪些字符的直观印象,请看看NSCharacterSet 提供的类方法:alphanumericCharacterSetcapitalizedLetterCharacterSetcontrolCharacterSetdecimalDigitCharacterSetdecomposableCharacterSetillegalCharacterSetletterCharacterSetlowercaseLetterCharacterSetnewlineCharacterSetnonBaseCharacterSetpunctuationCharacterSetsymbolCharacterSetuppercaseLetterCharacterSetwhitespaceAndNewlineCharacterSetwhitespaceCharacterSet与它的名字所表述的相反,NSCharacterSet 跟 NSSet 一点关系都没有。虽然底层实现不太一样,但是 NSCharacterSet 在概念上跟 NSIndexSet 还有点相似的。NSIndexSet,之前提到过,表示一个有序的不重复的无符号整数的集合。Unicode字符跟无符号整数类似,大致对应一些拼写表示。所以,一个 NSCharacterSet +lowercaseCharacterSet 字符集与一个包含97到122范围的 NSIndexSet 是等价的。现在我们对理解 NSCharacterSet 的基本概念已经有了少许自信,让我们来看一些它的模式与反模式吧:去掉空格NSString -stringByTrimmingCharactersInSet: 是个你需要牢牢记住的方法。它经常会传入 NSCharacterSet +whitespaceCharacterSet 或 +whitespaceAndNewlineCharacterSet 来删除输入字符串的头尾的空白符号。需要重点注意的是,这个方法 仅仅 去除了 开头 和 结尾 的指定字符集中连续字符。这就是说,如果你想去除单词之间的额外空格,请看下一步。挤压空格假设你去掉字符串两端的多余空格之后,还想去除单词之间的多余空格,这里有个非常简便的方法:Objective-CNSString *string = @"Lorem ipsum dolar sit amet.";string = [string stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];NSArray *components = [string componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];components = [components filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"self ''"]];string = [components componentsJoinedByString:@" "];首先,删除字符串首尾的空格;然后用 NSString -componentsSeparatedByCharactersInSet: 在空格处将字符串分割成一个 NSArray;再用一个 NSPredicate 去除空串;最后,用 NSArray -c...
2016-03-1108 miniOSDevLog
iOSDevLog396. nshipster-NSCachehttp://nshipster.cn/nscache/NSCacheMattt Thompson撰写、 Tony Li翻译、 发布于2012年7月14日可怜的 NSCache 一直处于 NSMutableDictionary 的阴影之下。就好像没有人知道它提供了垃圾处理的功能,而开发者们却费劲力气地去自己实现它。没错,NSCache 基本上就是一个会自动移除对象来释放内存的 NSMutableDictionary。无需响应内存警告或者使用计时器来清除缓存。唯一的不同之处是键对象不会像 NSMutableDictionary 中那样被复制,这实际上是它的一个优点(键不需要实现 NSCopying 协议)。如果开发者们知道就好了……但是,你并不像其他开发者那样,对吧?你应该不会小看 NSCache 的?这并不是说它没有一丝瑕疵和一些莫名其妙的问题。NSCache 就像是个烫手山芋。拿 setObject:forKey:cost: 来说,它和 setObject:forKey: 方法类似,但是带着 cost 参数。你可能会问,那是个什么东西?好吧,官方文档甚至都没有说清楚:cost 被用来计算缓存中所有对象的代价。当内存受限或者所有缓存对象的总代价超过了最大允许的值时,缓存会移除其中的一些对象。很好,目前为止还不错……然而,这个移除流程并不会保证顺序。后果就是,如果你期望通过控制 cost 的值来完成某些特殊行为的话,结果可能会对你的程序无益。啊?这是什么意思?通常,精确的 cost 应该是对象占用的字节数。如果它不可以直接读出来的话,你没必要费劲地去计算它,因为这么做的话会增加使用缓存的代价。等会儿,那不精确的 cost 值应该怎么计算呢?有什么计算内存占用的规则吗?比如按数量排序来计算?“随便瞎猜导致性能变差”似乎不会让人满意……如果你没有有效的值传入,那就传入 0,或者用 setObject:forKey: 方法,它不需要传入 cost 值。懂了:除非你在 Apple 工作并且认识写这个类的人,否则不要用这个方法。另外,它还有一套使用 evictsObjectsWithDiscardedContent 和 来控制对象是否会被自动移除的机制,但是这可能只会让你碰到更多的问题。尽管有上面提到的这些问题,开发者们还是应该多多使用 NSCache。你项目中任何你称之为缓存却不是 NSCache 对象的东西都应该被换成 NSCache。但是,如果你这么做了,务必要用你熟悉的那套 objectForKey:、setObject:forKey:、removeObjectForKey: 方法。作者Mattt ThompsonMattt ThompsonMattt Thompson (@mattt) is the creator & maintainer of AFNetworking and other popular open-source projects, including Postgres.app, ASCIIwwdc and Nomad.翻译者Tony Li下一篇文章NSSort​Descriptor排序:它是CS(计算机科学)入门课程考试和初级编程面试白板考题的主流考题。不管怎么样,你上一次真正需要知道如何实现快速排序是什么时侯?相关文章NSUUID /CFUUIDRef /UIDevice -uniqueIdentifier /-identifierForVendorUIReferenceLibraryViewController /DCSDictionaryRefCFBagNSValueTransformer 除非另有声明、本网站采用知识共享「署名-非商业性使用 3.0 中国大陆」许可协议授权。本站文章由 Croath Liu 、 、 Delisa Mason 、 Jack Flintermann 、 Mattt Thompson 、 、 Mike Lazer-Walker 、 Natasha Murashev 和 Nate Cook 撰写、 Andrew Yang 、 April Peng 、 Bob Liu 、 Candyan 、 Chester Liu 、 Croath Liu 、 David Liu 、 GWesley 、 Henry Lee 、 JJ Mao 、 Lin Xiangyu 、 Ricky Tan 、 Sheldon Huang 、 Tiny Tian 、 Tony Li 、 Yifan Xiao 、 Yu Jin 和 Zihan Xu 翻译。
2016-03-1003 miniOSDevLog
iOSDevLog395. nshipster-NSAssertion​Handlerhttp://nshipster.cn/nsassertionhandler/NSAssertion​HandlerMattt Thompson撰写、 Ricky Tan翻译、 发布于2013年2月25日“如果你一开始没有成功,用一个面向对象的注入点覆写默认的异常处理机制。”如果你是由 NSAssertionHandler 养大的话,这就是你小时候会学到的那种建议。编程结合了人类思考过程中众多学科,从高层次的辩论和语义学——我们用来解释一个系统如何工作的“故事”——到支撑所有一切的数学和哲学机器。断言是从经典的逻辑学中借用过来的概念。在逻辑学中,断言是对已经证明过的命题的陈述。在编程中,断言是指程序员所做出的关于应用程序在它们所声明的地方的一些假设。当用于先验条件和后验条件能力范围内时,断言形成了一种契约,它描述了代码在执行一个方法或函数的开始和结束时的状态的期望。断言也能用于加强运行时的条件,为了当先验条件失败时阻止程序运行。断言与单元测试有些类似,它们都定义了代码将会运行的期望结果。与单元测试不同的是,断言存在于程序本身,并且因此被限定在程序的上下文中。因为单元测试是完全独立的,它们完全有能力通过使用像方法桩和模拟对象等工具隔离并且单独测试特定的行为。开发者应当在应该程序中结合使用合理数量的断言和单元测试来测试和定义应用程序行为。基础断言处理Objective-C 用一个面向对象的途径混合了 C 语言风格的断言宏定义来注入和处理断言失败。即:NSAssertionHandler:每个线程拥有它自己的断言处理器,它是 NSAssertionHandler 类的实例对象。当被调用时,一个断言处理器打印一条包含方法和类名(或者函数名)的错误信息。然后它抛出一个 NSInternalInconsistencyException 异常。基础类库中定义了两套断言宏:NSAssert / NSCAssertNSParameterAssert / NSCParameterAssert基础类库从语义学上和功能性上使断言处理器的 API 在两个方面区别开来。第一个区别在于一般断言(NSAssert)和参数化断言(NSParameterAssert)。方法或函数应当在代码最开始处使用 NSParameterAssert / NSCParameterAssert 来强制输入的值满足先验条件,这是一条金科玉律;其他情况下使用 NSAssert / NSCAssert。第二个区别在于 C 和 Objective-C 的断言:NSAssert 应当只用于 Objective-C 环境中(即方法实现中),而 NSCAssert 应当只用于 C 环境中(即函数中)。当 NSAssert 或 NSParameterAssert 的条件不满足时,断言处理器会调用 -handleFailureInMethod:object:file:lineNumber:description: 方法。当 NSCAssert 或 NSCParameterAssert 的条件不满足时,断言处理器会调用 -handleFailureInFunction:file:lineNumber:description: 方法。另外,NSAssert / NSCAssert 也有一些变体,从 NSAssert1 到 NSAssert5,它们各自使用不同数量的参数用于 printf 风格的格式化字符串。使用 NSAssertionHandler值得注意的是,从 Xcode 4.2 开始,发布构建默认关闭了断言,它是通过定义 NS_BLOCK_ASSERTIONS 宏实现的。也就是说,当编译发布版时,任何调用 NSAssert 等的地方都被有效的移除了。尽管基础类库的断言宏在它们自己的权力下十分有用————虽然只用于开发之中————但是这件趣事不能就此停止。NSAssertionHandler 还提供了一套优雅地处理断言失败的方式来保留珍贵的现实世界的使用信息。据说,许多经验丰富的 Objective-C 开发者们告诫不要在生产环境中使用 NSAssertionHandler。基础类库中的断言处理是用来在一定安全距离外来理解和感激的。请小心行事如果你决定在对外发布版的应用中使用它。NSAssertionHandler 是一个很直接的类,带有两个需要在子类中实现的方法:-handleFailureInMethod:... (当 NSAssert / NSParameterAssert 失败时调用)和 -handleFailureInFunction:... (当 NSCAssert / NSCParameterAssert 失败时调用)。LoggingAssertionHandler 简单地打印出断言失败信息,但是那些信息也可以记录到外部的网络服务中去,用以聚集和分析。LoggingAssertionHandler.hObjective-C@interface LoggingAssertionHandler : NSAssertionHandler@endLoggingAssertionHandler.mObjective-C@implementation LoggingAssertionHandler- (void)handleFailureInMethod:(SEL)selector object:(id)object file:(NSString *)fileName lineNumber:(NSInteger)line description:(NSString *)format, ...{ NSLog(@"NSAssert Failure: Method %@ for object %@ in %@#%i", NSStringFromSelector(selector), object, fileName, line);}- (void)handleFailureInFunction:(NSString *)functionName file:(NSString *)fileName lineNumber:(NSInteger)line description:(NSString *)format, ...{ NSLog(@"NSCAssert Failure: Function (%@) in %@#%i", functionName, fileName, line);}@end每个线程都可以指定断言处理器。想设置一个 NSAssertionHandler 的子类来处理失败的断言,在线程的 threadDictionary 对象中设置 NSAssertionHandlerKey 字段即可。大部分情况下,你只需在 -application:didFinishLaunchingWithOptions: 中设置当前线程的断言处理器。AppDelegate.mObjective-C- (BOOL)application:(UIApplication *)applicationdidFinishLaunchingWithOptions:(NSDictionary *)launchOptions{ NSAssertionHandler *assertionHandler = [[LoggingAssertionHandler alloc] init]; [[[NSThread currentThread] threadDictionary] setValue:assertionHandler forKey:NSAssertionHandlerKey]; // ... return YES;}NSAssertionHandler 是提醒我们作为一个程序员如何通过断言语句清晰地表达我们的期望的一个最佳实践。但是如果我们进一步深入了解 NSAssertionHandler————当然,也深入我们自己内心,还有不少课程需要学习,有关我们的善意和同情心的底线的,有关我们谅解他人能力的,以及从我们自己的错误中恢复的。我们不可能永远都是对的。我们都会犯错。只有接受每个人都是有限的这个事实,我们才能独自成长。诸如此
2016-03-1007 miniOSDevLog
iOSDevLog393. nshipster-Key-Value Observing​http://nshipster.cn/key-value-observing/Key-Value ObservingMattt Thompson撰写、 Tiny Tian翻译、 发布于2013年10月7日问了几次研究 NSBlock 的人员:Key-Value Observing 在 Cocoa 框架里有着最不好用的 API 。它很难对付,啰嗦,令人迷惑。最糟糕的是,它的 API 掩盖了 framework 中很引人注目的特性。当处理复杂的,有状态的系统,book-keeping 对于保持清晰是很必要的。免的左手不知道右手做的事。随着时间的推移,对象需要一些方法来发布和订阅状态的改变。在 Objective-C 和 Cocoa 中,有许多事件之间进行通信的方式,并且每个都有不同程度的形式和耦合NSNotification & NSNotificationCenter 提供了一个中央枢纽,一个应用的任何部分都可能通知或者被通知应用的其他部分的变化。唯一需要做的是要知道在寻找什么,主要是通知的名字。例如,UIApplicationDidReceiveMemoryWarningNotification 是给应用发了一个内存不足的信号。Key-Value Observing 允许 ad-hoc,通过在特定对象之间监听一个特定的 keypath 的改变进行事件内省。例如:一个 ProgressView 可以观察 网络请求的 numberOfBytesRead 来更新它自己的 progress 属性。Delegate 是一个流行的传递事件的设计模式,通过定义一系列的方法来传递给指定的处理对象。例如:UIScrollView 每次它的 scroll offset 改变的时候都会发送 scrollViewDidScroll: 到它的代理Callbacks 不管是像 NSOperation 里的 completionBlock(当 isFinished==YES 的时候会触发),还是 C 里边的函数指针,传递一个函数钩子比如 SCNetworkReachabilitySetCallback(3)。在所有这些方法里,Key-Value Observing 是最不好理解的,所以这周 NSHipster 将致力于提供一些最佳实践来解决这一局面。对于一个普通用户,这个练习可能没什么意义,但是对订阅了本博客的人来说确很有用。 或者 KVO,是一个非正式协议,它定义了对象之间观察和通知状态改变的通用机制的。作为一个非正式协议,你不会看到类的这种引以为豪的一致性(只是隐式的假定了 NSObject 的所有子类)。KVO 的中心思想其实是相当引人注意的。任意一个对象都可以订阅以便被通知到其他对象状态的改变。这个过程大部分是内建的,自动的,透明的。题外话,这种观察者模式类似的表现是最现代框架的秘诀,比如 Backbone.js 和 Ember.js。注册对象可以让观察者添加一个特定的 keypath,这个在这篇文章中描述过,其实就是用点符号分隔的 key 指定了一系列的属性。在大多数情况下,这些都是对象的顶级属性。添加一个观察者的方法是 –addObserver:forKeyPath:options:context::Objective-C- (void)addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(void *)contextobserver:注册 KVO 通知的对象。观察者必须实现 key-value observing 方法 observeValueForKeyPath:ofObject:change:context:。keyPath:观察者的属性的 keypath,相对于接受者,值不能是 nil。options: NSKeyValueObservingOptions 的组合,它指定了观察通知中包含了什么,可以查看 "NSKeyValueObservingOptions"。context:在 observeValueForKeyPath:ofObject:change:context: 传给 observer 参数的随机数据让这个API不堪入目的事实就是最后两个参数经常是 0 和 NULL。options 代表 NSKeyValueObservingOptions 的位掩码,需要注意 NSKeyValueObservingOptionNew & NSKeyValueObservingOptionOld ,因为这些是你经常要用到的,可以跳过 NSKeyValueObservingOptionInitial & NSKeyValueObservingOptionPrior:NSKeyValueObservingOptionsNSKeyValueObservingOptionNew: 表明变化的字典应该提供新的属性值,如何可以的话。NSKeyValueObservingOptionOld: 表明变化的字典应该包含旧的属性值,如何可以的话。NSKeyValueObservingOptionInitial: 如果被指定,一个通知会立刻发送到观察者,甚至在观察者注册方法之前就返回,改变的字典需要包含一个 NSKeyValueChangeNewKey 入口,如果 NSKeyValueObservingOptionNew 也被指定的话,但从来不会包含一个NSKeyValueChangeOldKey 入口。(在一个 initial notification 里,观察者的当前属性可能是旧的,但对观察者来说是新的),你可以使用这个选项代替显式的调用,同时,代码也会被观察者的 observeValueForKeyPath:ofObject:change:context: 方法调用,当这个选项被用于 addObserver:forKeyPath:options:context:,一个通知将会发送到每个被观察者添加进去的索引对象中。NSKeyValueObservingOptionPrior:是否各自的通知应该在每个改变前后发送到观察者,而不是在改变之后发送一个单独的通知。一个通知中的可变数组在改变发生之前发送经常包含一个 NSKeyValueChangeNotificationIsPriorKey 入口且它的值是 @YES,但从来不会包含一个 NSKeyValueChangeNewKey 入口。当这个选项被指定,在改变之后发送的通知中的变化的字典包含了一个与在选项没有被指定的情况下应该包含的同一个入口,当观察者自己的键值观察需要它的时候,你可以使用这个选项来调用 -willChange... 方法中的一个来观察它自己的某个属性,那个属性的
2016-03-1014 miniOSDevLog
iOSDevLog394. nshipster-MKLocal​Search​http://nshipster.cn/mklocalsearch/MKLocal​SearchMattt Thompson撰写、 April Peng翻译、 发布于2013年4月29日是的,我们知道的:人们对 Apple 的地图很无所适从。本应该是 iOS 6 至高无上的新特性,却由于其尴尬的不准确定位以及移除了公共交通信息让官方出来为之道歉。沉浸在这所有的沸沸嚷嚷中,你可能完全没有注意到在 iOS 6.1 的 MapKit 里新增加的一个小部件:MKLocalSearch。MKLocalSearch 允许开发者得到一个地理区域内附近的兴趣点。但在你急于去使用 MKLocalSearch 之前,你必须了解一些它的朋友的事情。你看,MKLocalSearch 是有区别于 MKLocalSearchRequest 和 MKLocalSearchResponse 的功能的:SwiftObjective-Clet request = MKLocalSearchRequest()request.naturalLanguageQuery = "Restaurants"request.region = mapView.regionlet search = MKLocalSearch(request: request)search.startWithCompletionHandler { (response, error) in for item in response.mapItems { // ... }}像一个 “动物标本剥制师” 一样,MKLocalSearchRequest 需要一个 naturalLanguageQuery 和一个可选的边界地域 region 来约束结果。在实践中,region 通常从一个 MKMapView 传进来。MKLocalSearchResponse 在 MKLocalSearch -startWithCompletionHandler: 的同名 block handler 中被返回,并且返回一个 MKMapItem 对象的数组。每个 MKMapItem 通过 placemark 属性包含了诸如 name,phoneNumber,url 和地址这样的信息。如果你保持一个 MKLocalSearch 对象的引用,你可以选择性的像 -viewWillDisappear: 或之类的一样来 -cancel 请求。重点在哪儿?MKLocalSearch 是一种相对直接的 API(尽管也许更糟的是它仅是一个简单的单类接口)......所以有什么大不了的?API 的限制。 或者说,它们的缺陷。让我来解释一下:或许关于 iOS 6 中 MapKit 最反直觉的事情是 它仍然被广泛的使用。别去管 “苹果地图门” 的闹剧,即使从 Google 和 MapBox 引入了非常棒的 iOS 地图 SDK,开发者们仍在使用 MapKit.有部分原因可能是审美问题,但更多的则是因为主场优势。由于 MapKit 与 UIKit 紧密联系,它可以更容易,更广泛地由第三方开发者定制。这把我们带回到了 API 调用的限制。当用另一种地图 SDK 或地理空间 Web 服务开发的时候,许可条款几乎必然比苹果公司免费提供的更为有限。免费是一个艰难的问题,而且更没得选的是区域性加载或调用 API 的时候不用担心越过 API 的限制。我们还能做什么呢?通过引入 MKLocalSearch,在类似的场景中,苹果提供了越来越多的原生 API。扩展的地理空间搜索?或者是 iTunes 流媒体的第一方 API?毕竟,人们可以敢于梦想...MKLocalSearch 提供了一种简单的方法来找到当地兴趣点。由于其无争议的 web 服务集成,以及与 MapKit 的紧密集成,任何基于位置的应用程序都该好好地利用它。作
2016-03-1004 miniOSDevLog
iOSDevLog392. nshipster-KVC Collection OperatorsKVC Collection OperatorsMattt Thompson撰写、 Candyan翻译、 发布于2012年12月3日Ruby爱好者总爱嘲笑Objective-C臃肿的语法。尽管新的Object Literals特性让我们的语法瘦了几斤,但那些红头发的恶霸们还总是用他们的单行map和花哨的Symbol#to_proc来嘲讽我们。实际上,一门语言是否优雅归结起来就是其怎么样能更好的避免循环。for,while语句是一种拖累;即使是快速枚举也一样。无论你怎么样使他们看起来更加的友好,循环依然是一个在自然语言中用非常简单方式描述所做事情的代码块"给我这个列表里面所有员工的平均薪酬",等等。。。Objective-Cdouble totalSalary = 0.0;for (Employee *employee in employees) { totalSalary += [employee.salary doubleValue];}double averageSalary = totalSalary / [employees count];╮(╯_╰)╭幸运的是,键-值编码给我们了一种更加简洁的,几乎像Ruby一样的方式来做这件事:Objective-C[employees valueForKeyPath:@"@avg.salary"];KVC集合运算符允许在valueForKeyPath:方法中使用key path符号在一个集合中执行方法。无论什么时候你在key path中看见了@,它都代表了一个特定的集合方法,其结果可以被返回或者链接,就像其他的key path一样。集合运算符会根据其返回值的不同分为以下三种类型:简单的集合运算符 返回的是strings, number, 或者 dates对象运算符 返回的是一个数组数组和集合运算符 返回的是一个数组或者集合要理解其工作原理,最好方式就是去action里面看看。想象一个Product类和一个由以下数据所组成的products数组:Objective-C@interface Product : NSObject@property NSString *name;@property double price;@property NSDate *launchedOn;@end键-值 编码会在必要的时候把基本数据类型的数据自动装箱和拆箱到NSNumber或者NSValue中来确保一切工作正常。Name Price Launch DateiPhone 5 $199 September 21, 2012iPad Mini $329 November 2, 2012MacBook Pro $1699 June 11, 2012iMac $1299 November 2, 2012简单集合操作符@count: 返回一个值为集合中对象总数的NSNumber对象。@sum: 首先把集合中的每个对象都转换为double类型,然后计算其总,最后返回一个值为这个总和的NSNumber对象。@avg: Takes the double value of each object in the collection, and returns the average value as an NSNumber.@max: 使用compare:方法来确定最大值。所以为了让其正常工作,集合中所有的对象都必须支持和另一个对象的比较。@min: 和@max一样,但是返回的是集合中的最小值。例如:Objective-C[products valueForKeyPath:@"@count"]; // 4[products valueForKeyPath:@"@sum.price"]; // 3526.00[products valueForKeyPath:@"@avg.price"]; // 881.50[products valueForKeyPath:@"@max.price"]; // 1699.00[prod...
2016-03-1009 miniOSDevLog
iOSDevLog388. nshipster-CGGeometryhttp://nshipster.cn/cggeometry/CGGeometryMattt Thompson撰写、 Ricky Tan翻译、 发布于2012年12月17日除非你是一个数学极客或者一个古希腊人,否则几何学应该不是你高中时最喜欢的课程。不过你可能就是班里的那种学生,那种会老老实实把所有公式都输进TI-8X图形计算器里去看结果。对于那些在学习TI-BASIC花的时间多于欧式几何的人,这里有一份iOS和OS X上绘图系统Quartz 2D的备忘录:CGPoint 是个表示二维坐标系中的点的结构体。在 iOS中,坐标原点在左上方,所以向右和向下分别是 x 和 y 的正方向。相反,在 OS X 中 (0, 0) 在左下方, y 的正方向朝上。CGSize 是个表示 长 和 宽 的结构体。CGRect 是个包含一个 CGPoint (原点)和一个 CGSize (大小)的结构体,表示一个在 原点 处画 大小 中表示的 长 和 宽 的矩形。正因为 CGRect 用于表示屏幕上绘制的所有视图的 frame,一个程序员操作矩形几何体的能力决定着他在图形编程上的成功。幸运的是,Quartz 带来了一批好用的函数,减少了本应该我们自己做的浮点数学运算。即使 Cocoa 中视图编程非常重要,即使这些函数都非常有用,但它们对于大部分 iOS 开发者说来仍是相对陌生的。这个情况不会持续太久!让我们来了解一下这些最有用的函数,并帮你们节省一些编程的工作量吧!变换我们的列表中的第一个是几何变换。这些函数返回在传入的矩形中做某些特定操作后的 CGRectCGRectOffsetCGRectOffset: 返回一个原点在源矩形基础上进行了偏移的矩形。Objective-CCGRect CGRectOffset( CGRect rect, CGFloat dx, CGFloat dy)注意,用这个你只改变了矩形的原点。它不仅能让你在同时改变水平和垂直位置的时候减少一行代码,更重要的是,它所表示的平移比直接分开操作原点的值更具有几何意义。CGRectInsetCGRectInset: 返回一个与源矩形共中心点的,或大些或小些的新矩形。Objective-CCGRect CGRectInset( CGRect rect, CGFloat dx, CGFloat dy)想一个视图中的视图更好看吗?用CGRectInset给它设置一个 10pt 的边距吧。需要记住的是,矩形将围绕它的中心点进行缩放,左右分别增减dx(总共2 x dx),上下分别增减 dy(总共 2 x dy)。如果你用 CGRectInset 作为缩放矩形的快捷方法,一般通用的做法是嵌套调用CGRectOffset,把CGRectInset的返回值作为CGRectOffset的参数。CGRectIntegralCGRectIntegral: 返回包围源矩形的最小整数矩形。Objective-CCGRect CGRectIntegral ( CGRect rect)将CGRect 取整到最近的完整点是非常重要的。小数值会让边框画在像素边界处。因为像素已经是最小单元(不能再细分),小数值会使绘制时取周围几个像素的平均值,这样看起来就模糊了。CGRectIntegral 将表示原点的值向下取整,表示大小的值向上取整,这样就保证了你的绘制代码平整地对齐到像素边界。作为一个经验性的原则,如果你在执行任何一个可能产生小数值的操作(例如除法,CGGetMid[X|Y],或是 CGRectDivide),在把一矩形作为视图的边框之前应该用CGRectIntegral正则化它。从技术上讲,坐标系讲的是点,而视网膜屏一个点中有四个像素,所以它在奇数像素± 0.5f处绘制也不会产生模糊。取值辅助函数这些函数提供了取特定CGRect的有意思的尺寸值的便捷方法。CGRectGet[Min|Mid|Max][X|Y]CGRectGetMinXCGRectGetMinYCGRectGetMidXCGRectGetMidYCGRectGetMaxXCGRectGetMaxY这六个函数返回矩形x或y的最小、中间或最大值,原型如下:Objective-CCGFloat CGRectGet[Min|Mid|Max][X|Y] ( CGRect rect)用这些函数代替诸如frame.origin.x + frame.size.width之类的代码将更加清晰、语义上更为生动的(特别是用取中间和取最大函数)。CGRectGet[Width|Height]CGRectGetHeight: 返回矩形的高度。Objective-CCGFloat CGRec
2016-03-0812 miniOSDevLog
iOSDevLog387. nshipster-CFString​Transformhttp://nshipster.cn/cfstringtransform/CFString​TransformMattt Thompson撰写、 Ricky Tan翻译、 发布于2012年8月6日关于一种语言好不好用,你只需要衡量以下两种指标:API 的统一性String 类的实现质量NSString 是基础类库中的佼佼者。在那个其他语言 仍在 艰难地正理处理 Unicode 的时代,NSString 是尤其让人印象深刻的。不仅仅是任何内容扔在它里面就能 正确工作 ,NSString 还能将字符串解析成语法标签、检测出内容中的首要语言,并且在任意你能想到的字符编码中转换。它好用得离谱。它虽然很强大,但是不提提它的可无缝转换(toll-free bridged)的表兄弟 CFMutableString,或者更特殊的 CFStringTransform,是不负责任的。正如它的 CF 前缀所表述的一样,CFStringTransform 是 Core Foundation 中的一部分。这个函数传入以下参数,并返回一个 Boolean 来表示转换是否成功:string: 需要转换的字符串。由于这个参数是 CFMutableStringRef 类型,一个 NSMutableString 类型也可以通过自由桥接的方式传入。range: 转换操作作用的范围。这个参数是 CFRange,而不是 NSRange。transform: 需要应用的变换。这个参数使用了包含下面将提到的字符串常量的 ICU transform string。reverse: 如有需要,是否返回反转过的变换。CFStringTransform 中的 transform 参数涉及的内容很多。这里有个它能做什么的概述:去掉重音和变音符Énġlišh långuãge lẳcks iñterêßţing diaçrïtičş. 如此类的字符串,把扩展的拉丁字符集正则化为 ASCII 友好型的表示,它非常有用。用 kCFStringTransformStripCombiningMarks 变换来去掉任意字符串中弯弯扭扭的符号。为 Unicode 字符命名kCFStringTransformToUnicodeName 让你可以找出特殊字符的 Unicode 标准名,包括 Emoji。例如:"✨" 被转换成 "{SHEEP} {DASH SYMBOL} {SPARKLES}",而 "" 变成了 "{PIG FACE}"。不同拼写之间转写除了英语这个重大例外(和它那令人愉快的拼写不一致),书写系统一般是将语言音调编码成一致的符号表示。欧洲语言一般使用拉丁字母(外加一些变音符),俄罗斯用西里尔字母,日本用平假名和片假名,泰国、韩国和阿拉伯国家也都有自己的字母。虽然每种语言都有特殊的音调列表,也许有些其他语言会缺失,所有主要书写系统的交集已经足以让你高效的在不同字母之间转写(不要跟翻译搞混了)。CFStringTransform 可以在拉丁语和阿拉伯语、西里尔语、希腊语、韩语(韩国)、希伯来语、日语(平假名和片假名)、普通话、泰语之间来回转写。Transformation Input OutputkCFStringTransformLatinArabic mrḥbạ مرحباkCFStringTransformLatinCyrillic privet приветkCFStringTransformLatinGreek geiá sou γειά σουkCFStringTransformLatinHangul annyeonghaseyo 안녕하세요kCFStringTransformLatinHebrew şlwm שלוםkCFStringTransformLatinHiragana hiragana ひらがなkCFStringTransformLatinKatakana katakana カタカナkCFStringTransformLatinThai s̄wạs̄dī สวัสดีkCFStringTransformHiraganaKatakana にほんご ニホンゴkCFStringTransformMandarinLatin 中文 zhōng wén并且这只是用了核心类库中常量定义!直接传入一个ICU transform表达式,CFStringTransform 还可以在拉丁语和阿拉伯语、亚美尼亚语、注音、西里尔字母、格鲁吉亚语、希腊语、汉语、韩语、希伯来语、平假名、印度语(梵文,古吉拉特语,旁遮普文,卡纳达语,马拉雅拉姆语,奥里雅语,泰米尔语,特卢固)、朝鲜语、片假名、叙利亚语、塔纳文、泰语之间转写。正则化用户产生的内容字符串变换的一个更实际的应用是正则化不可预知的用户输入。即使你的应用并不单独处理其他语言,你也应当能智能地处理用户向你的应用输入的任何内容。例如,你想在设备上建立一个可搜索的电影索引,它包含世界各地的人的问候:首先,应用 kCFStringTransformToLatin 变换将所有非英文文本转换为拉丁字母表示。Hello! こんにちは! สวัสดี! مرحبا! 您好! → Hello! kon'nichiha! s̄wạs̄dī! mrḥbạ! nín hǎo!然后,应用 kCFStringTransformStripCombiningMarks 变换来去除变音符和重音。Hello! kon'nichiha! s̄wạs̄dī! mrḥbạ! nín hǎo! → Hello! kon'nichiha! swasdi! mrhba! nin hao!最后,用 CFStringLowercase 转为小写,并用CFStringTokenizer 分词用作文本的索引。(hello, kon'nichiha, swasdi, mrhba, nin, hao)通过对用户输入的文本使用同样的变换,你就可以实现一个通用的搜索,无论搜索文本或内容是什么语言!CFStringTransform 会是个用来按你的要求处理语言的十分强大的工具。并且它是,且仅仅是等着你勇敢地投入Objective-C的温暖怀抱的许多强大特性之一。作者Mattt ThompsonMattt ThompsonMattt Tho
2016-03-0809 miniOSDevLog
iOSDevLog386. nshipster-CFBaghttp://nshipster.cn/cfbag/CFBagMattt Thompson撰写、 Croath Liu翻译、 发布于2012年8月27日Objective-C被夹在了两个世界中间。在其中一边的世界里,Objective-C遵循着经过深思熟虑的、发扬自[Smalltalk]的面向对象哲学理念,这种理念给我们带来了消息传递和参数命名法等好点子。另一边的世界里则避免不了有很多C的残留思想带来强大的力量和一坨混乱。越来越多@符号的使用证明了这个一致性危机。Foundation和Core Foundation的关系里也可以发现这种一致性问题,特别是那一堆无缝连接的类: NSArray / CFArray, NSDictionary / CFDictionary, NSSet / CFSet。这些类可以通过C函数和Objective-C方法传入传出而不需要手动转换。这是抽象化设计的缺陷,但是同时也是写应用时最实用的优化最难以优化部分的绝佳手段。但是这种无缝连接是Foundation和Core Foundation之间集合类型转换的一个例外:Foundation Core Foundation 无缝转换NSArray* CFArray* ✓NSCountedSet CFBag* N/A CFBinaryHeap N/A CFBitVector* NSDictionary* CFDictionary* ✓NSIndexSet* N/A NSMapTable N/A NSOrderedSet N/A NSPointerArray N/A NSPointerFunctions N/A NSSet* CFSet* ✓* 代表同样适用于相应的mutable类型看表格的第二行, NSCountedSet 和 CFBag。注意:不像Foundation和Core Foundation中的其他类型,他们之间不能无缝转换。相关文档中除了提供了 NSCountedSet 的一些简略信息,没有其他实在的内容能解释存在这样的类型转换方式。。我猜是因为 NSCountedSet 没有对应的可变(mutable)类型,于是这就打破了类似 NSArray 那些支持无缝转换的固有模式。Bag,一种抽象数据类型在计算机科学领域集合数据类型的殿堂中,bag没有数组、集合、联合数组、树、图、优先队列那么占有一席之地。其实bag本身就很晦涩,你可能从没听过这东西。Bag,或者叫做multiset,是set的一种变体,不同的是bag里同一数据可以出现不止一次。集合中每一个唯一元素会有一个合计数字与其绑定。类似set一样,bag也是顺序不敏感的。用bag的场景有...咳咳...很少,但有如果它出现你肯定能感觉到那就是bag。大选中统计票数?模拟家庭作业中的概率分布?实现一个Yahtzee骰子游戏?Bag都是你的新选择!使用CFMutableBagCFBag 和它的可变类型同类 CFMutableBag 作为bag类型的具体实现,都是非常灵活的。虽然它们没有像 NSCountedSet 那样方便地面向对象化,但它可以进行的自定义行为却是多种多样的。你可以用带有许多回调的初始化函数来建立一个 CFBag ,这些回调函数定义在 CFBagCallBacks 结构中,该结构详细描述了一个值被插入、删除、比较的方法:Objective-Cstruct CFBagCallBacks { CFIndex version; CFBagRetainCallBack retain; CFBagReleaseCallBack release; CFBagCopyDescriptionCallBack copyDescription; CFBagEqualCallBack equal; CFBagHashCallBack hash;};typedef struct CFBagCallBack
2016-03-0707 miniOSDevLog
iOSDevLog385. nshipster-Address​Book​UIAddress​Book​UIMattt Thompson撰写、 Henry Lee翻译、 发布于2012年10月15日Address Book UI是用来在用户地址簿展示、选择、编辑和创建联系人的iOS框架。与Message UI框架相似,Address Book UI包含了一些可以用dismissViewControllerAnimated:completion:方法来展示的试图控制器,它通过一些统一的接口提供常用的系统功能。要用到这个框架,你需要添加AddressBook.framework和AddressBookUI.framework两个框架到你工程中build phase的"Link Binary With Libraries"之下。乍一看你可能觉得Address Book UI没有什么特别的地方。其实,在iOS 6里,MFMailComposeViewController和ABNewPersonViewController有一些非常棒的内部处理小伎俩在起着作用,Ole Begemann就有一篇很棒的、非常值得读的关于远程视图控制器的文章。抛开剩下的View Controller和协议,Address Book UI还有一个功能十分惊人地有用。ABCreateStringWithAddressDictionary()函数返回一个已经本地化、结构化的地址字符串组。关于这个函数第一个要讨论的问题是包含这些组成结构的字典,这个字典是由以下的常量作为键值的。kABPersonAddressStreetKeykABPersonAddressCityKeykABPersonAddressStateKeykABPersonAddressZIPKeykABPersonAddressCountryKeykABPersonAddressCountryCodeKeykABPersonAddressCountryCodeKey 是一个尤其重要的属性,它决定了用来格式化地址字符串的语言。如果你对国家代码不是很确定或者没有确定的国家代码数据集,你可以通过NSLocale像这样来确定:Objective-C[mutableAddressComponents setValue:[[[NSLocale alloc] initWithIdentifier:@"en_US"] objectForKey:NSLocaleCountryCode] forKey:(__bridge NSString *)kABPersonAddressCountryCodeKey];在其他任何框架里你都找不到实用性这么好的功能,这不需要用到NSLocale,甚至也不需要Map Kit和Core Location来定位。苹果尽了如此多的努力来提高很多本地化的细节,而你会很惊奇这么一个重要的功能被放在了一个模糊不清、感觉上不怎么相关的一个框架里。不过,电话簿UI在OS X里不提供,似乎这个平台也没有其他相同功能的内容。你看,地址格式会因为地区的不同相差很大,例如,美国的地址是下面这个格式的:Street Address City State ZIP Country而日本的地址的表示则有不同的习惯:Postal Code Prefecture Municipality Street Address Country这个和不同地区有不同的全角半角逗号一样烦人,所以,你还是在展示结构化的地址的时候尽量多地用这些函数把。还有一个很棒的利用已经本地化的地址簿的方式就是FormatterKit,他在它的1.1版中添加了TTTAddressFormatter。作者Mattt ThompsonMattt ThompsonMattt Thompson (@mattt) is the creator & maintainer of AFNetworking and other popular open-source projects, including Postgres.app, ASCIIwwdc and Nomad.翻译者Henry Lee爱好广泛的 iOS 工程师。下一篇文章NSLinguistic​TaggerNSLinguisticTagger在语言学功能上来讲是一把名副其实的瑞士军刀,它可以讲自然语言的字符串标记为单词、确定词性和词根、划分出人名地名和组织名称、告诉你字符串使用的语言和语系。相关文章NSURLCacheNSLinguisticTaggerNSSortDescriptorUIApplicationDelegate launchOptions 除非另有声明、本网站采用知识共享「署名-非商业性使用 3.0 中国大陆」许可协议授权。本站文章由 Croath Liu 、 、 Delisa Mason 、
2016-03-0705 miniPhreaks2015-12-2349 miniPhreaks2015-12-2349 minThe NSNorth Podcast2014-01-2919 miniPhreaks2014-01-0947 miniPhreaks2014-01-0947 miniPhreaks2013-12-1251 miniPhreaks2013-12-1251 minBuild Phase2013-10-0937 minChangelog Interviews2013-08-0651 minThe Changelog: Software Development, Open Source2013-08-0651 minDeveloping Perspective2013-01-0314 minNSBrief2012-08-2052 min