Objective-C的泛型


WWDC2015的明星是Swift。在Swift语言到2.0以后会被开源,这其中包括了protocol扩展和一个新的错误处理API。 苹果的小baby已经长成,并且意料之中的获得了开发者的关注。但是在iOS开发中Object-C并不会很快的推出历史舞台。 并且在WWDC2015中介绍了ObjC的一个很好地特性。我们下面就来谈一谈ObjC的这个新特性:泛型

我们先看一看下面的代码:


 
 
class Person : NSObject { let name : String let surname : String var friends : [ Person ] ? init ( name : String , surname : String ) { self . name = name self . surname = surname } }

非常简单。这里定义了一个名为Person的类。虽然更应该被定义为一个struct,但是为了和ObjC做对比就先定义为类了。 这个类里面定义了一个属性friends,一个Person对象组成的数组。Swift的数组是泛型的,可以包括Swift里面有的所有类型。 现在,假设我们有一个Person的对象,我们需要他的第一个朋友的名字。


 
 
let firstFriendName = person . friends ? . first ? . name

编译器知道person.friends是一个optional的包含Person对象的数组。所以firstFriendName是一个可空的字符串

很好,那么在ObjC里是怎么样的呢?


 
 
@interface Person : NSObject @property ( nonatomic , copy , nonnull ) NSString * name ; @property ( nonatomic , copy , nonnull ) NSString * surname ; @property ( nonatomic , strong , nullable ) NSArray * friends ; @end

在我们继续之前,我们先来聊一下nonnullnullable这两个修饰符。这些叫做可空声明,是在Xcode6.3中引入的。 __nullable可以有nil或者NULL值,而__nonnull不可以。如果你不遵守这些规则,那么是编译不过的。

现在,我们可以回到泛型。我们无法在friends数组中定义元素类型。参考Swift的例子,假设我们有类Person的对象, 而且我们需要第一个朋友的名字。由于没有泛型,我们首先需要取到朋友数组的第一个元素。


 
 
id firstFriend = person . friends . firstObject ;

由于Objective-C里没有泛型,person.friends.fristObject只能定义为id类型的,而不是Person。 id是一个可以指向任意类型的对象的指针,也就是id指针指向的对象可以是任意类型的。 我们完全不能明确的知道person.friends.firstObject是一个Person对象。我们只能假设person.friends.firstObject是一个Person对象, 但是可以是NSString类型的对象。


 
 
Person * firstFriend = person . friends . firstObject ; NSString * fristFriendWrongTypeVariable = person . friends . firstObject ;

实用正确类型的对象是我们需要处理的。如果我们用了一个错误的类型,那么在运行时这个对象会接受到一个不支持的message, 这样就会报错了。要获取第一个朋友的名字,我们需要初始化另外的一个变量:


 
 
Person * firstFriend = person . friends . firstObject ; NSString * firstFriendName = firstFriend . name

这个例子非常简单,但是却明显的表明了ObjC需要额外多写一些代码,而且开发者,而不是编译器,需要负责类型的安全。

如果说ObjC急需什么Swift或者Java、C#早就已经有的特性的话,那么就一定是泛型了。幸好,Xcode7带来了一个轻量级的ObjC泛型。


 
 
@interface Person : NSObject @property ( nonatomic , copy , nonnull ) NSString * name ; @property ( nonatomic , copy , nonnull ) NSString * surname ; @property ( nonatomic , strong , nullable ) NSArray < Person * > * friends ; @end

现在我们可以定义集合里的元素类型了。


 
 
NSString * firstFriendName = person . friends . firstObject . name ;

编译器知道firstFriendName是NSString类型的。如果我们给一个变量赋值一个错误的类型的对象会发生什么呢?


 
 
NSDate * firstFriendName = person . friends . firstObject . name ;

我们会收到一个warning

Swift会如何引入这个ObjC的Person类呢


 
 
var name : String var surname : String var friends : [ Person ] ?

轻量的泛型不止适用于NSArray。还适用于其他两个基础集合类-NSDictionaryNSSet


 
 
@property NSSet < Person * > * people ;

 
 
@property NSDictionary < NSString * , Person * > * people ;

另外,我们也可以在我们自定义的类型中使用这些轻量级的泛型:


 
 
@interface MyCustomClass < T > : NSObject - ( void ) doSomethingWithGeneric : ( T ) object ; @end @implementation MyCustomClass - ( void ) doSomethingWithGeneric : ( id ) object { } @end

 
 
MyCustomClass < NSString * > * myCostomObject = [ [ MyCustomClass alloc ] init ] ; [ myCostomObject doSomethingWithGeneric : @ " hello, world " ] ;

如果我们使用错误的类型呢?


 
 
[ myCostomObject doSomethingWithGeneric : @100 ] ;

Xcode会给出一个警告。

但是有些东西需要注意:ObjC的自定义泛型类和泛型的集合在引入Swift之后行为并不一样。 NSArrayNSSetNSDictionary的类型在Swift中还是可用的。但是自定义的类的泛型参数在Swift中就不可用了。 所有的自定义类型又变回了AnyObject

Xcode7引入了轻量级泛型有什么好处呢?极大地减少了类型转换的代码。类型检测的责任从开发者转移到了编译器。 代码更加干净,类型更加安全。但是,这并不是全部。在Xcode7前,Swift调用ObjC的framework要非常小心。 每一个ObjC的集合元素都需要从AnyObject类型做转换。引入了泛型之后就把ObjC和Swift的互操作的这个问题解决了。


from:https://netguru.co/blog/objective-c-generics

欢迎加群互相学习,共同进步。QQ群:iOS: 58099570 | Android: 330987132 | nodejs:329118122 | Go-Scala:217696290 | Python:336880185 | 做人要厚道,转载请注明出处!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值