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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM