Swift with Cocoa and Object-C(第一部分)

Interacting with Objective-C APIs(与OC-API的交互)###

Initialization(初始化)####

要使用Swift初始化一个Objecive-C的类,只要使用Swift调用这个类的其中一个构造函数。
OC通常使用init初始化,或者如果实例对象需要带一个或多个参数使用initWith:,当OC的初始化转化为Swift,init前缀是一个关键字,暗含了Swift初始化方法。如果初始化带一个参数,With从选择器的后边移除之后成为相应的命名参数。

下面是OC的初始化声明:

- (instancetype)init;
- (instancetype)initWithFrame:(CGRect)frame
                         style:(UITableViewStyle)style;

相同的Swift初始化声明:

 init() {/*...*/} 
 init(frame: CGRect, style: UITableViewStyle) {/*...*/}

在初始化的时候OC和Swift还是有明显不同的.
在OC中,你这么做:

UITableView *myTableView = [[UITableView alloc] initWithFrame:CGRectZero style:UITableViewStyleGrouped];

在Swift中,你这么做:

let myTableView: UITableView = UITableView(frame: CGRectZero, style: .Grouped)

注意你不需要调用alloc;Swift会自动为你处理。当调用Swift初始化的时候也不会出现init.

当你给一个常量或变量赋值的时候,你可以明确的标明类型,或者你也可以去掉类型,Swift可以从初始化自动推理类型.

let myTextField = UITextField(frame: CGRect(x: 0.0, y: 0.0, width: 200.0, height: 200.0))

Class Factory Methods and Convenience Initializers(类工厂方法和方便的初始化)####

对于连贯性和简便性,在Swift中OC的类工厂方法是重要的简便的。初始化允许他们用相同的编译器。

例如,在OC中你可以这样调用工厂方法:

UIColor *color = [UIColor colorWithRed:0.5 green:0.0 blue:0.5 alpha:1.0];

在Swift中,你可以这么调用:

let color = UIColor(red: 0.5, green: 0.0, blue: 0.5, alpha: 1.0)

Failable Initialization(可失败的初始化)####

在OC中,直接初始化返回初始化对象。当初始化失败的时候为了通知调用者,OC的初始化可以返回nil.在Swift中,这个模式被构建为语言特性叫做failable initialization(可失败的初始化)

许多OC的初始化在系统的framework被审查用来表明初始化是否可能失败.你可以在自己的类用空指针表明初始化是否失败,描述在这里 Nullability and Optionals.OC初始化表明是否失败等同于init(...)表明如果初始化不失败,或者init?(...)表明如果初始化失败.另外,OC初始化也可以为init!(...).

例如,UIImage(contentsOfFile:)初始化可能失败,如果提供的路径图片不存在.如果初始化是成功的你可以使用可选值绑定对失败的结果进行解包.

if let image = UIImage(contentsOfFile: "MyImage.png") {
    // loaded the image successfully
} else {
    // could not load the image
}

Accessing Properties(访问属性)####

OC用@property属性声明和下列Swift的属性声明是一样的:

  • Properties用(nonnull, nullable, null_resettable)的空属性等同于Swift在Nullability and Optionals可选或不可选类型.
  • Properties用readonly标记的属性等同于Swift的getter { get }.
  • Properties用weak标记的属性等同于Swift用weak关键字标记(weak).
  • 所有的属性并非都是weak(也有assign, copy, strong , unsafe_unretained)等同于Swift有关的存储属性.
  • Properties用class属性等同于Swift的属性
  • Atomicity属性(atomicnonatomic)不会在Swift的属性声明中响应,但是当Swift的重要的属性访问得时候,OC的原子性保护依然保持.
  • 在Swift访问属性(getter=setter=)被忽略.

OC对象在Swift中访问属性,用属性名不带括号.
例如,你可以设置用如下代码UITextFieldtextColortext:

myTextField.textColor = UIColor.darkGray()
myTextField.text = "Hello World"

Working with Methods###

在Swift中,你可以调用OC的方法使用点语法.

当OC的方法转化为Swift时,OC选择器的第一部分会成为方法名并且出现在括号前。第一个参数将直接在括号里边,并且没有名字。余下的参数名与参数则一一对应的填在括号中。

例如,在OC中你可以这么做:

[myTable insertSubview:mySubview atIndex:2];

在Swift中,你可以这么做:

myTableView.insertSubview(mySubview, at: 2)

如果你调用无参方法,你必须加上括号。

myTableView.layoutIfNeeded()

id Compatibility###

Swift包含一个AnyObject的协议对象,这个就好比是OC的id类型。AnyObject 协议可以让你写出类型安全的代码的同时维持无类型对象的通用性。因为AnyObject协议保证了这种安全,Swift将id对象导入为AnyObject。

例如,id,你可以为AnyObject类型的对象分配任何其他类型的对象。你也同样可以为它重新分配其他类型的对象。

var myObject: AnyObject = UITableViewCell()
myObject = NSDate()

你也可以在调用Objective-C方法或者访问属性时不将它转换为具体类的类型。包括Objcive-C中标记为@objc的方法。

let futureDate = myObject.addingTimeInterval(10)
let timeSinceNow = myObject.timeIntervalSinceNow

Unrecognized Selectors and Optional Chaining###

因为AnyObject对象的类型只有在运行时才能知道,所以我们不经意间,就写出了不安全的代码。另外,与Objective-C不一样的是,如果你调用方法或者访问的属性AnyObject 对象没有声明,将会报运行时错误。例如,下面的代码将会在运行时抛出unrecognized selector error

myObject.character(at: 5)
// crash, myObject doesn't respond to that method

尽管如此,你也可以借助Swift的optionals特性来排除这个Objective-C中常见的错误,当你用AnyObject对象调用一个Objective-C的方法,这次调用将会变成一次隐式展开optional(implicitly unwrapped optional)的行为。你可以通过optional特性来决定AnyObject类型的对象是否调用该方法,同样的,你可以把这种特性应用在属性上。

例如,在下列代码,第一行和第二行不会检查,因为count属性和character(at:)方法在NSDate对象不存在。myCount被推测为一个可选的Int类型,并且被设置为nil.你可以使用if-let声明来展开这个方法的返回值,就像第三行一样:

// myObject has AnyObject type and NSDate value
let myCount = myObject.count
/// myCount has Int? type and nil value
let myChar = myObject.character?(at: 5)
// myChar has unichar? type and nil value
if let fifthCharacter = myObject.character?(at: 5) {
    print ("Found \(fifthCharacter) at index 5")
}
// conditional branch not executed

Downcasting AnyObject###

在处理泛型,类型是已知或可以合理肯定的时候,把这些对象转为更具体的类型。然而,因为泛型可能是任意一种类型,不一定能够成功的转为具体的类型。

你可以用条件类型转化操作(as?),它可以返回一个你尝试转化类型的可选值:

let userDefaults = UserDefaults.standard
let lastRefreshDate: AnyObject? = userDefaults.object(forKey: "LastRefreshDate")
if let date = lastRefreshDate as? NSDate {
    print("\(date.timeIntervalSinceReferenceDate)")
}

如果你确定对象类型,你可以使用強转操作(as!)代替。

let myDate = lastRefreshDate as! NSDate
let timeInterval = myDate.timeIntervalSinceReferenceDate

然而,如果强制转化失败,运行时会出错:

let myDate = lastRefreshDate as! NSString //Error

Nullability and Optionals###

在OC中,你引用的对象的原始指针可能为NULL(也可能为nil)。在Swift中,所有的值–包括结构体与对象的引用–都被保证为非空。作为替代,你将这个可以为空的值包装为optional type。当你需要指示该值为空,你需要使用nil,你可以阅读更多关于Optionals的内容。

OC可以用空指针来指定参数类型,属性类型,或者返回类型,也可以用NULLnil。单独的类型声明用_Nullable_Nonnull指针可能被检查,单独的属性声明用nullable,nonnullnull_resettable属性可能被检查,或者全部使用NS_ASSUME_NONNULL_BEGINNS_ASSUME_NONNULL_END宏都可能被检查。如果一个类型不是空信息,Swift不会区分可选与不可选的,作为隐形解析可选。

  • 类型声明为非空,带_Nonnull指针或在检查区域,在Swift中是不可选的。
  • 类型声明为空,带_Nullable指针,在Swift中可选。
  • 类型声明不带空指针,在Swift是一个隐士解析可选

例如,看下列OC声明:

@property (nullable) id nullbaleProperty;
@property (nonnull) id nonNullProperty;
@property id unannotatedProperty;

NS_ASSUME_NONNULL_BEGIN
- (id)returnsNonNullValue;
- (void)takesNonNullParameter:(id)value;
NS_ASSUME_NONNULL_EDN

- (nullable id)returnsNullableValue;
- (void)takesNullableParameter:(nullable id)value;

- (id)returnsUnannotatedValue;
- (void)takesUnannotatedParameter:(id)value;

Swift写法:

var nullableProperty: AnyObject?
var nonNullProperty: AnyObject
var unannotatedProperty: AnyObject!
 
func returnsNonNullValue() -> AnyObject
func takesNonNullParameter(value: AnyObject)
 
func returnsNullableValue() -> AnyObject?
func takesNullableParameter(value: AnyObject?)
 
func returnsUnannotatedValue() -> AnyObject!
func takesUnannotatedParameter(value: AnyObject!)

大多OC的系统frameworks,包含Foundation,早已提供空注释,允许
你惯用和类型安全的方式使用值。

未完待续...

Swift with Cocoa and Object-C(第二部分)

你可能感兴趣的:(Swift with Cocoa and Object-C(第一部分))