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(第二部分)

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,717评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,501评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,311评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,417评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,500评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,538评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,557评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,310评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,759评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,065评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,233评论 1 343
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,909评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,548评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,172评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,420评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,103评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,098评论 2 352

推荐阅读更多精彩内容