類型推斷是一個非常普遍的特性峡扩,在當下的現(xiàn)代語言像Swift, Kotlin 等。幸運的是,類似的效果可以在Xcode 8之后的C或objective - C中通過__auto_type來實現(xiàn)擴展尾菇。
現(xiàn)在我一直在使用在__auto_type基礎(chǔ)之上的宏。
#define let __auto_type const
#define var __auto_type
長類型的signatures
類型簽名可以變得非常長刹孔。
NSDictionary<NSString *, NSDictionary<NSIndexPath *, ASCollectionElement *> *> *supplementElementDict = [elementMap supplementaryElements];
每次你想聲明一個supplementaryElements這段長的返回值泳秀。__auto_type這將變得更短,它仍然能夠知道supplementElementDict是什么。
let supplementElementDict = [elementMap supplementaryElements];
let常量
Swift的一個好處是讓最常用和方便的方式聲明變量不變朱沃。與此同時const也存在于C和objective - C,但幾乎沒有人真正使用它:
NSString *const name = @"Michael";
用__auto_type可讓代碼可讀性更高:
let name = @"Michael";
泛型類型的“光”苞轿??逗物?
通常使用一個方法返回對象是否支持泛型像NSArray或NSDictionary你必須顯式地聲明返回類型搬卒。讓我們舉個例子使用這段代碼:
// Takes in an NSArray<NSString *> *
static void processSomePeople(NSArray<NSString *> *peoples) {
NSCParameterAssert([peoples isKindOfClass:[NSArray class]]);
for (NSString *people in peoples) {
NSCAssert([people isKindOfClass:[NSString class]], @"Should be a NSString");
// Do some more with people
}
}
// Returns NSArray<NSNumber *> *
static NSArray<NSNumber *> *somePeopleNumbers() {
return @[@1, @2, @3];
}
__auto_type會自動推斷從somePeopleNumbers()返回的泛型。下面的代碼將發(fā)出一個警告翎卓。
let people = somePeopleNumbers(); // Returns a NSArray<NSNumber *> *
processSomePeople(people); // Takes a NSArray<NSString *> *
如果你不聲明通用具體來說,下面的代碼在編譯時不會發(fā)出警告的泛型類型NSArray不是顯式聲明契邀。
NSArray *people = somePeopleNumbers(); // Return type is NSArray<NSNumber *>
processSomePeople(people); // Will take in a NSArray<NSString *>
內(nèi)聯(lián)block的類型推斷
如果你曾經(jīng)聲明內(nèi)聯(lián)塊你就會知道寫所有的類型簽名多痛苦。當使用__auto_type塊類型將自動推斷和看起來更熟悉分配一個變量在其他類型失暴。
// Block variable signature
void (^block)(id, NSUInteger, BOOL *) = ^(id obj, NSUInteger idx, BOOL *stop) {
// Do something
};
[array enumerateObjectsUsingBlock:block];
// Inferred block
let block = ^(id obj, NSUInteger idx, BOOL *stop) {
// Do something
};
[array enumerateObjectsUsingBlock:block];
和Swift類似
熟悉Swift的let 和 var 或者 C++的 auto / const auto在使用let 和 var 的時候會非常習慣坯门。這不是一個大賣點,但這讓開發(fā)人員更容易找到每天多次在不同的語言之間跳躍。
問題:如何推斷nullability類型
在您的代碼中使用__auto_type有一個問題逗扒。目前__auto_type不繼承nullability推斷類型古戴。進一步的信息在:https://openradar.appspot.com/27062504。
我認為優(yōu)點大于缺點是事實,你必須明確地寫下每一個變量簽名可以為空,得到nullability類型的編譯器的警告矩肩。例如我們來看下面的代碼允瞧。
// Takes in a nonnull NSString
static void removeUserFromCacheWithId:(NSString * _Nonnull greeting) {
// Try to remove the user from the cache
}
// Returns either a NSString or nil
static NSString * _Nullable currentUserId() {
if (arc4random() % 2 == 0) {
return @"100";
} else {
return nil;
}
}
下面的代碼使用上面的函數(shù)聲明將發(fā)出一個編譯器警告作為一個可以為空指針將被傳遞到一個函數(shù),它接受一個null指針。
// This will emit a warning while compiling
removeUserFromCacheWithId(currentUserId());
// This will emit a warning while compiling too
NSString *_Nullable userId = currentUserId();
removeUserFromCacheWithId(userId);
正如你所看到的在上面的示例中,得到一個編譯器警告你必須顯式地聲明返回類型的指針currentUserId nullable()蛮拔。如果你不聲明它可以為空或使用__auto_type不會出現(xiàn)像下面的代碼將展示警告述暂。
// All of them are NOT emitting a warning while compiling
// BUT - The latest Clang static analyzer emits:
// Warning: Nullable pointer is passed to a callee that
// requires a non-null argument for both cases
NSString *userId = currentUserId();
// or
let userId = currentUserId();
removeUserFromCacheWithId(userId);
如果你使用靜態(tài)分析器將為你捕獲和顯示一個警告任何情況下。
總結(jié)
我希望我能給你幾個原因為什么我認為__auto_type在代碼中使用是一件好事,但是最后你必須決定如果優(yōu)點多于缺點,你會覺得在你的代碼中使用它非常舒適建炫。