北京时间2月10日,苹果在面向开发者推送iOS 8.3 Beta的同时,还发布了版本号为6D520o的Xcode 6.3 Beta,其中便包含了iOS 8.3 Beta和OS X v10.10 SDK,并进一步提升了Swift与Objective-C代码的交互性,而Swift业已更新至1.2版本。
从 Xcode 6.3 Beta Release Notes 看出,Xcode 6.3 Beta包含了很多颇为值得开发者期待的改变,共计50多处改动,同时修改了Objective-C的语法,足见苹果对Swift语言的重视。而其代码迁移工具可以帮助开发者将其代码从Swift 1.1(Xcode 6.1)升级至Swift 1.2(Xcode 6.3),具体执行编辑菜单(Edit)->转换(Convert)-至(To)Swift1.2即可。 具体更新如下:
Swift语言的增强
if let a = foo(), b = bar() where a < b, let c = baz() { }
它允许你测试多种选择,并且包含一个bool判断。当然这种情况不包含嵌套判断。
let x: SomeThing if condition { x = foo() } else { x = bar() } use(x)
这个正常的来说需要var变量用法,尽管这里没有任何修改的操作。
1.含有单返回语句的闭包现在类型检查时以单表达式闭包处理。
2.匿名的且含有非空返回类型的单表达式现在可以用在Void上下文中。
3.多表达式的闭包类型的情况可能无法被类型推断出来,这归功于缺乏返回类型的情况能被正确的推断出来。
@objc enum Bear: Int { case Black, Grizzly, Polar }<br>
导出到Objective-C:
typedef NS_ENUM(NSInteger, Bear) { BearBlack, BearGrizzly, BearPolar };
import Darwin var devNullStat = stat() stat("/dev/null", &devNullStat)
如果一个结构体的元素不能被正确的初始化为0(比如被标记为新的_nonnull标示符时),这个默认的构造器将会终止。
String的索引类型间新的转换API现在可以用了,如String、
toString(Int.self) // 打印 “Swift.Int" println([Float].self) // 打印 "Swift.Array<Swift.Float>” println((Int, String).self) // 打印 "(Swift.Int, Swift.String)"
func autoreleasepool(@noescape code: () -> ()) { pushAutoreleasePool() code() popAutoreleasePool() }
Swift语言的改变
import Foundation func log(s: String) { println(x) } let ns: NSString = "some NSString" // Okay log(ns) // 错误 // "'NSString' 不能转换为 'String'"
为了完成桥接转换,需要用显式转化符标注:
log(ns as String) // succeeds
从Swift类型到Objective-C类型的桥接隐式转换依然被允许,比如:
func nsLog(ns: NSString) { println(ns) } let s: String = “some String” nsLog(s) // okay: implicit conversion from String to NSString is still permitted
//以前我们这样写: func assert(predicate : @autoclosure () -> Bool) {… } //现在需要这样写: func assert(@autoclosure predicate : () -> Bool) {… }
func curryUnnamed(a: Int)(_ b: Int) { return a + b } curryUnnamed(1)(2) func curryNamed(first a: Int)(second b: Int) -> Int { return a + b } curryNamed(first: 1)(second: 2)
class A : NSObject { var property: String = "Hello" // 注意: Objective-C 方法 'setProperty:’ // 以前这里“属性”这里是通过setter声明 } extension A { func setProperty(str: String) { } // 错误:方法"setProperty" // 重复声明了Objective-C方法 //'setProperty:' }
同样地检查在Objective-C中重写:
class B : NSObject { func method(arg: String) { } // 注意:重写操作 // 这里含有类型:'(String) -> ()' } class C : B { func method(arg: [String]) { } // 错误: 重写的选择器方法含有不匹配的类型'([String]) -> ()' }
和协议的适配性一样:
class MyDelegate : NSObject, NSURLSessionDelegate { func URLSession(session: NSURLSession, didBecomeInvalidWithError: Bool){ } // 错误:Objective-C 方法 'URLSession:didBecomeInvalidWithError:' //由方法提供: 'URLSession(_:didBecomeInvalidWithError:)' // 和可选类型的需求方法相冲突: // 'URLSession(_:didBecomeInvalidWithError:)' 在协议 // 'NSURLSessionDelegate' }
Swift语言Bug修复
struct Point { var x, y: Double } extension Point : Printable { var description: String { return "(/(x), /(y))" } } var p1 = Point(x: 1.5, y: 2.5) println(p1) // prints "(1.5, 2.5)”
let animationCurve = unsafeBitCast(userInfo[UIKeyboardAnimationCurveUserInfoKey].integerValue, UIViewAnimationCurve.self)
现在可以写为:
let animationCurve = UIViewAnimationCurve(rawValue: userInfo[UIKeyboardAnimationCurveUserInfoKey].integerValue)!
class Base { func foo(x: String) -> String? { return x } } class Derived: Base { override func foo(x: String?) -> String { return x! } }
关于Objective-C语言的增强
Objective-C API中可以表示参数,返回值,属性,变量等等的“nullability”属性。比如,下面是表达很多UITableView API的为空特性:
-(void)registerNib:(nonnull UINib *)nib forCellReuseIdentifier:(nonnull NSString *)identifier; -(nullable UITableViewCell *)cellForRowAtIndexPath:(nonnull NSIndexPath)indexPath; @property (nonatomic, readwrite, retain, nullable) UIView *backgroundView;
这个nullability标示符影响了Objective-C API在Swift的可选类型值,nonnull标示符标示的类型将会以非可选的类型的导入,这个用来替代隐式解封可选类型如(e.g., UINib!)。而nullable标示符标示的类型则会以可选类型导入(如UITableViewCell?),所以下面的API在Swift中表现如下:
func registerNib(nib: UINib, forCellReuseIdentifier identifier: String) func cellForRowAtIndexPath(indexPath: NSIndexPath) -> UITableViewCell? var backgroundView: UIView?
void enumerateStrings(__nonnull CFStringRef (^ __nullable callback)(void));
这里,它自身的回调函数是nullable的,但是它的回调函数的返回类型为nonnull,所以这个API在Swift以如下方式使用:
func enumerateStrings(callback: (() -> CFString)?)
总的来说,可空特性标示符有三种,可以用双下划线(用在任何指针类型),或者没有下划线的(用在Objective-C属性,方法结果类型或者方法参数类型)。
#pragma clang assume_nonnull begin // … -(void)registerNib:(UINib *)nib forCellReuseIdentifier:(NSString *)identifier; -(nullable UITableViewCell *)cellForRowAtIndexPath:(NSIndexPath)indexPath; @property (nonatomic, readwrite, retain, nullable) UIView *backgroundView; // … #pragma clang assume_nonnull end
@property (nonatomic, retain, null_resettable) UIColor *tintColor;
这样的API在Swift使用隐式强制解封的方法使用:
var tintColor: UIColor!
void executeImmediately(__attribute__((noescape)) void (^callback)(void);
将被影射到Swift为:
func executeImmediately(@noescape callback: () -> Void)
作者简介:
王芳杰 目前就职于叠拓信息技术有限公司,担任叠拓NGN中国人力资源培养经理、叠拓NGN中国售前经理,《老码说编程之玩转Swift江湖》一书作者。