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

Objective-C的泛型的更多相关文章

  1. Automake

    Automake是用来根据Makefile.am生成Makefile.in的工具 标准Makefile目标 'make all' Build programs, libraries, document ...

  2. iOS开发——新特性OC篇&Objective新特性

    Objective新特性 Overview 自 WWDC 2015 推出和开源 Swift 2.0 后,大家对 Swift 的热情又一次高涨起来,在羡慕创业公司的朋友们大谈 Swift 新特性的同时, ...

  3. Objective C (iOS) for Qt C++ Developers(iOS开发,Qt开发人员需要了解什么?)

    Qt/C++开发人员眼中的Obj-C      对于我们第一次自己定义iOS应用来说,对于来自Qt/C++开发人员来说,我不得不学习Objective-C相关语法与知识 为了让读者可以更easy理解这 ...

  4. 一起学 Java(三) 集合框架、数据结构、泛型

    一.Java 集合框架 集合框架是一个用来代表和操纵集合的统一架构.所有的集合框架都包含如下内容: 接口:是代表集合的抽象数据类型.接口允许集合独立操纵其代表的细节.在面向对象的语言,接口通常形成一个 ...

  5. .NET面试题系列[8] - 泛型

    “可变性是以一种类型安全的方式,将一个对象作为另一个对象来使用.“ - Jon Skeet .NET面试题系列目录 .NET面试题系列[1] - .NET框架基础知识(1) .NET面试题系列[2] ...

  6. C#4.0泛型的协变,逆变深入剖析

    C#4.0中有一个新特性:协变与逆变.可能很多人在开发过程中不常用到,但是深入的了解他们,肯定是有好处的. 协变和逆变体现在泛型的接口和委托上面,也就是对泛型参数的声明,可以声明为协变,或者逆变.什么 ...

  7. 编写高质量代码:改善Java程序的151个建议(第7章:泛型和反射___建议106~109)

    建议106:动态代理可以使代理模式更加灵活 Java的反射框架提供了动态代理(Dynamic Proxy)机制,允许在运行期对目标类生成代理,避免重复开发.我们知道一个静态代理是通过主题角色(Prox ...

  8. 6.在MVC中使用泛型仓储模式和依赖注入实现增删查改

    原文链接:http://www.c-sharpcorner.com/UploadFile/3d39b4/crud-operations-using-the-generic-repository-pat ...

  9. C#泛型详解(转)

    初步理解泛型: http://www.cnblogs.com/wilber2013/p/4291435.html 泛型中的类型约束和类型推断 http://www.cnblogs.com/wilber ...

  10. C# 泛型

    C# 泛型 1.定义泛型类 在类定义中包含尖括号语法,即可创建泛型类: class MyGenericClass<T> { //Add code } 其中T可以遵循C#命名规则的任意字符. ...

随机推荐

  1. IOS安卓常见问题

    一.IOS自带safari浏览器   1.safari不支持fixed+input输入框.   解决方案: http://www.haorooms.com/post/ios_fixed_input   ...

  2. mysql --secure-file-priv is set to NULL.Operations related to importing and exporting data are disabled

    --secure-file-priv is set to NULL. Operations related to importing and exporting data are disabledmy ...

  3. Linux移植之子目录下的built-in.o生成过程分析

    在Linux移植之make uImage编译过程分析中罗列出了最后链接生成vmlinux的过程.可以看到在每个子目录下都有一个built-in.o文件.对于此产生了疑问built-in.o文件是根据什 ...

  4. Oracle_高级功能(9) 性能优化

    1.oracle优化器 优化目标分为4种: choose (选择性) rule (基于规则) first rows(第一行) all rows(所有行) Description:描述sql的执行计划 ...

  5. android开发中一个activity如何调用另一个xml中的控件

    有时候,我们需要在一个activity中使用另一个activity中的控件,这时候就不能直接findViewById,不然会报错指向空对象,这时就需要像下面这样做. LayoutInflater fa ...

  6. redis 哨兵(sentinel)

    redis哨兵 哨兵自动故障转移 自动通知应用最新master信息 无需担心,master挂了,程序不需要修改IP啥的,由哨兵自动完成 修改sentinel.conf protected-mode n ...

  7. spring MVC中Dubbo的配置

    1.服务提供方的bubbo配置: <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi=& ...

  8. lazarus的动态方法和虚拟方法

    动态方法和虚拟方法在delphi里面分别表示: 动态方法 当需要调用父类.祖先类的被覆盖方法的时候,是查找继承树,当找到,就调用.减少了VMT占用,但调用慢一些. 虚拟方法 和动态方法不同的是,记录了 ...

  9. linux以16进制方式查看文件

    vim打开文件 :%!xxd  以16进制查看 :%!xxd -r  转回来

  10. Linux网络端口命名规则,一致性网络设备命名

    参考文档: https://www.cnblogs.com/pipci/p/9229571.html 一致性网络设备命名,即Consistent Network Device Naming. 一.服务 ...