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. golang 通过fsnotify监控文件,并通过文件变化重启程序

    一.下载我们需要的包 > go get github.com/fsnotify/fsnotify 二.使用fsnotify监控文件 package main; import ( "gi ...

  2. Beyound Compare中比较java字节码class文件

    背景 项目维护的时候版本混乱或者外出在现场项目排错的时候难免要比对两个jar/class/war文件的源代码. 通常情况下这个时候我们用jd-gui直接把文件拖进去比对,这种情况只适合单一文件的比对. ...

  3. vi/vim 按键说明

    转自:http://www.runoob.com/linux/linux-vim.html vi/vim 按键说明 除了上面简易范例的 i, Esc, :wq 之外,其实 vim 还有非常多的按键可以 ...

  4. python 面向对象编程 之 元类

    元类是类的类,使我们自定义的类,即我们用class定义类本质就是元类,是类的模板 四步走: 一:控制class定义类的过程 1.先拿到类名 2.在拿到基类 3.执行类体代码,得到名称空间的dict 4 ...

  5. 使用clear来清除localStorage保存对象的全部数据

    <!doctype html> <html> <head> <meta charset="utf-8"> <title> ...

  6. Activity(活动)

  7. iOS.Info.plist

    1. Custom message when asking for Address Book Permissions http://kevinyavno.com/blog/?p=176

  8. 基于稀疏表(Sparse Table)的RMQ(区间最值问题)

    在RMQ的其他实现方法中,有一种叫做ST的算法比较常见. [构建] dp[i][j]表示的是从i起连续的2j个数xi,xi+1,xi+2,...xi+2j-1( 区间为[i,i+2j-1] )的最值. ...

  9. python基础之Day5

    一.基本概念 为什么要有数据: 计算机能够像人一样识别现实生活中的状态是因为计算机事先将数据存到了记忆中 为什么要分类型: 满足现实世界不同状态的需要 二.数据类型(研究定义,作用,常见操作) 1.整 ...

  10. Ubuntu安装bcmath扩展

    sudo apt-get install php-bcmath