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. [z]Linux下压缩与解压

    1.压缩命令: 命令格式:tar  -zcvf   压缩文件名.tar.gz   被压缩文件名 可先切换到当前目录下.压缩文件名和被压缩文件名都可加入路径. 2.解压缩命令: 命令格式:tar  -z ...

  2. JS正则表达式验证是否为11位有效手机号码

    function isPoneAvailable($poneInput) { var myreg=/^[1][3,4,5,7,8][0-9]{9}$/; if (!myreg.test($poneIn ...

  3. VSCode一直弹框错误Linter pylint is not installed

    确保已经安装Python编译环境 点击下图位置(这个是我已经安装过后的文字,原本显示“搜索Python”字样) 点击后显示如下,点击安装 然后出现一大坨命令 最终出现“Successfully ins ...

  4. Java并发-ThreadGroup获取所有线程

    一:获取当前项目所有线程 public Thread[] findAllThread(){ ThreadGroup currentGroup =Thread.currentThread().getTh ...

  5. JAVA课堂练习-动手动脑--数组

    1.阅读并运行示例PassArray.java,观察并分析程序输出的结果,小结,然后与下页幻灯片所讲的内容进行对照. 源代码: public class PassArray { public stat ...

  6. linux 文件搜索

    locate  文件名 在后台数据库中按文件名搜索,搜索速度快,不用遍历整个操作系统 /var/lib/mlocate locate 命令所搜索的后台数据库 updatedb 手动更新数据库 新建的文 ...

  7. (转)Oracle 使用 DBLINK详解

    DBLINK详解 1.创建dblink语法: CREATE [PUBLIC] DATABASE LINK link CONNECT TO username IDENTIFIED BY password ...

  8. hdu 5475(2015上海网赛) An easy problem

    题目;http://acm.hdu.edu.cn/showproblem.php?pid=5475 题意就是给X赋初值1,然后给Q个操作,每个操作对应一个整数M:如果操作是1则将X乘以对应的M,如果是 ...

  9. Luogu 1273 有线电视网 - 树形背包

    Description 树形背包, 遍历到一个节点, 枚举它的每个子节点要选择多少个用户进行转移. Code #include<cstring> #include<cstdio> ...

  10. linux ubuntu R 无法安装rggobi包的原因及解决方案

    错误信息 Package'libxml-2.0',requiredby'ggobi',notfound     错误原因 ggobi缺乏libxml依赖 解决方案 sudo apt install l ...