类型推断是一个非常普遍的特性,在当下的现代语言像Swift, Kotlin 等。幸运的是,类似的效果可以在Xcode 8之后的C或objective - C中通过__auto_type来实现扩展。
现在我一直在使用在__auto_type基础之上的宏。
#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()返回的泛型。下面的代码将发出一个警告。
let people = somePeopleNumbers(); // Returns a NSArray<NSNumber *> *
processSomePeople(people); // Takes a NSArray<NSString *> *
如果你不声明通用具体来说,下面的代码在编译时不会发出警告的泛型类型NSArray不是显式声明。
NSArray *people = somePeopleNumbers(); // Return type is NSArray<NSNumber *>
processSomePeople(people); // Will take in a NSArray<NSString *>
内联block的类型推断
如果你曾经声明内联块你就会知道写所有的类型签名多痛苦。当使用__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 的时候会非常习惯。这不是一个大卖点,但这让开发人员更容易找到每天多次在不同的语言之间跳跃。
问题:如何推断nullability类型
在您的代码中使用__auto_type有一个问题。目前__auto_type不继承nullability推断类型。进一步的信息在:https://openradar.appspot.com/27062504。
我认为优点大于缺点是事实,你必须明确地写下每一个变量签名可以为空,得到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;
}
}
下面的代码使用上面的函数声明将发出一个编译器警告作为一个可以为空指针将被传递到一个函数,它接受一个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不会出现像下面的代码将展示警告。
// 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);
如果你使用静态分析器将为你捕获和显示一个警告任何情况下。
总结
我希望我能给你几个原因为什么我认为__auto_type在代码中使用是一件好事,但是最后你必须决定如果优点多于缺点,你会觉得在你的代码中使用它非常舒适。