Objective-C的泛型

 

WWDC2015的明星是Swift。在Swift語言到2.0之後會被開源,這其中包括了protocol擴展和一個新的錯誤處理API。 蘋果的小baby已經長成,而且意料之中的得到了開發者的關注。可是在iOS開發中Object-C並不會很快的推出歷史舞臺。 而且在WWDC2015中介紹了ObjC的一個很好地特性。咱們下面就來談一談ObjC的這個新特性:泛型objective-c

咱們先看一看下面的代碼:swift

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裏是怎麼樣的呢?curl

@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不能夠。若是你不遵照這些規則,那麼是編譯不過的。ide

如今,咱們能夠回到泛型。咱們沒法在friends數組中定義元素類型。參考Swift的例子,假設咱們有類Person的對象, 並且咱們須要第一個朋友的名字。因爲沒有泛型,咱們首先須要取到朋友數組的第一個元素。atom

id firstFriend = person.friends.firstObject;

因爲Objective-C裏沒有泛型,person.friends.fristObject只能定義爲id類型的,而不是Person。 id是一個能夠指向任意類型的對象的指針,也就是id指針指向的對象能夠是任意類型的。 咱們徹底不能明確的知道person.friends.firstObject是一個Person對象。咱們只能假設person.friends.firstObject是一個Person對象, 可是能夠是NSString類型的對象。url

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

實用正確類型的對象是咱們須要處理的。若是咱們用了一個錯誤的類型,那麼在運行時這個對象會接受到一個不支持的message, 這樣就會報錯了。要獲取第一個朋友的名字,咱們須要初始化另外的一個變量:spa

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

相關文章
相關標籤/搜索