用Swift處理動(dòng)態(tài)類型的方法和對(duì)象

? ? ?在Objective-C中猴鲫,id類型表示任何Objective-C類的實(shí)例對(duì)象松靡。相反允跑,Swift將id類型導(dǎo)入為任意類型键俱。當(dāng)您將一個(gè)Swift實(shí)例傳遞給Objective-C API時(shí)兰绣,它將作為id參數(shù)橋接,以便在API中作為Objective-C對(duì)象使用编振。當(dāng)id值作為任意值導(dǎo)入到Swift時(shí)缀辩,運(yùn)行時(shí)將自動(dòng)處理到類引用或值類型的橋接臭埋。


?? ? 向下轉(zhuǎn)換對(duì)象以調(diào)用方法和訪問屬性

?? ? 當(dāng)您使用任何您知道底層類型的類型對(duì)象時(shí),通常將這些對(duì)象向下轉(zhuǎn)換為底層類型是非常有用的臀玄。但是瓢阴,因?yàn)槿魏晤愋投伎梢砸萌魏晤愋停跃幾g器不能保證將向下轉(zhuǎn)換為更特定的類型健无。


?? ? 您可以使用條件類型轉(zhuǎn)換操作符(as?)荣恐,它返回一個(gè)可選的值领追,該值是您嘗試向下轉(zhuǎn)換到的類型的可選值:

?? ? let userDefaults = UserDefaults.standard

?? ? let lastRefreshDate = userDefaults.object(forKey: "LastRefreshDate") // lastRefreshDate is of type Any?

?? ? if let date = lastRefreshDate as? Date {

?? ? print("\(date.timeIntervalSinceReferenceDate)")

?? ? }



?? ? 如果您完全確定對(duì)象的類型居触,那么可以使用強(qiáng)制向下轉(zhuǎn)換操作符(as!)

?? ? let myDate = lastRefreshDate as! Date

?? ? let timeInterval = myDate.timeIntervalSinceReferenceDate


?概述

?? ? 一些類似Objective-C api的目標(biāo)-操作-接受方法或?qū)傩悦鳛閰?shù),然后使用這些名稱動(dòng)態(tài)調(diào)用或訪問方法或?qū)傩允T赟wift中臼膏,使用#selector和#keyPath表達(dá)式分別將這些方法或?qū)傩悦硎緸檫x擇器或密鑰路徑硼被。


?? ? 使用選擇器來安排對(duì)Objective-C方法的調(diào)用

?? ? 在Objective-C中,選擇器是引用Objective-C方法名稱的類型渗磅。在Swift中嚷硫,Objective-C選擇器由選擇器結(jié)構(gòu)表示,使用# Selector表達(dá)式創(chuàng)建它們始鱼。


?? ? 在Swift中仔掸,通過將方法的名稱放在#selector表達(dá)式:#selector(MyViewController.tappedButton(_:))中,可以為Objective-C方法創(chuàng)建選擇器风响。要構(gòu)造屬性的Objective-C getter或setter方法的選擇器嘉汰,使用getter:或setter: label作為屬性名的前綴,比如#selector(getter: MyViewController.myButton)状勤。下面的示例顯示了作為目標(biāo)-操作模式一部分使用的選擇器,用于調(diào)用響應(yīng)touchUpInside事件的方法双泪。




?? ? import UIKit

?? ? class MyViewController: UIViewController {

?? ? let myButton = UIButton(frame: CGRect(x: 0, y: 0, width: 100, height: 50))


?? ? override init(nibName nibNameOrNil: NSNib.Name?, bundle nibBundleOrNil: Bundle?) {

?? ? super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)

?? ? let action = #selector(MyViewController.tappedButton)

?? ? myButton.addTarget(self, action: action, forControlEvents: .touchUpInside)

?? ? }


?? ? @objc func tappedButton(_ sender: UIButton?) {

?? ? print("tapped button")

?? ? }


?? ? required init?(coder: NSCoder) {

?? ? super.init(coder: coder)

?? ? }

?? ? }


?? ? 如果需要消除重載函數(shù)之間的歧義持搜,請(qǐng)使用括號(hào)表達(dá)式和as運(yùn)算符使#選擇器表達(dá)式明確地指向特定的重載。


?? ? 使用關(guān)鍵路徑動(dòng)態(tài)訪問Objective-C屬性

?? ? 在Objective-C中焙矛,鍵是標(biāo)識(shí)對(duì)象特定屬性的字符串葫盼。鍵路徑是一個(gè)點(diǎn)分隔鍵字符串,它指定要遍歷的對(duì)象屬性序列村斟。鍵和鍵路徑經(jīng)常用于鍵值編碼(KVC)贫导,這是一種使用字符串標(biāo)識(shí)符間接訪問對(duì)象屬性和關(guān)系的機(jī)制。




?? ? 使用#keyPath字符串表達(dá)式創(chuàng)建編譯器選中的鍵和鍵路徑蟆盹,KVC方法可以使用這些鍵和路徑孩灯,比如value(forKey:)和value(forKeyPath:)。#keyPath字符串表達(dá)式接受鏈?zhǔn)椒椒ɑ驅(qū)傩砸糜饫摹K€支持通過鏈中的可選值鏈接峰档,比如#keyPath(Person.bestFriend.name)。使用#keyPath字符串表達(dá)式創(chuàng)建的鍵路徑不會(huì)傳遞有關(guān)它們引用的屬性或方法的類型信息,這些屬性或方法引用接受鍵路徑的api讥巡。


?? ? 下面的示例定義了一個(gè)Person類掀亩,創(chuàng)建了它的兩個(gè)實(shí)例,并使用幾個(gè)#keyPath字符串表達(dá)式來訪問這些屬性的屬性:


?? ? class Person: NSObject {

?? ? @objc var name: String

?? ? @objc var friends: [Person] = []

?? ? @objc var bestFriend: Person? = nil


?? ? init(name: String) {

?? ? self.name = name

?? ? }

?? ? }


?? ? let gabrielle = Person(name: "Gabrielle")

?? ? let jim = Person(name: "Jim")

?? ? let yuanyuan = Person(name: "Yuanyuan")

?? ? gabrielle.friends = [jim, yuanyuan]

?? ? gabrielle.bestFriend = yuanyuan


?? ? #keyPath(Person.name)

?? ? // "name"

?? ? gabrielle.value(forKey: #keyPath(Person.name))

?? ? // "Gabrielle"

?? ? #keyPath(Person.bestFriend.name)

?? ? // "bestFriend.name"

?? ? gabrielle.value(forKeyPath: #keyPath(Person.bestFriend.name))

?? ? // "Yuanyuan"

?? ? #keyPath(Person.friends.name)

?? ? // "friends.name"

?? ? gabrielle.value(forKeyPath: #keyPath(Person.friends.name))

?? ? // ["Yuanyuan", "Jim"]


將Objective-C導(dǎo)入Swift

使用Swift訪問Objective-C代碼中的類和其他聲明欢顷。


您可以在單個(gè)項(xiàng)目中同時(shí)使用Objective-C和Swift文件槽棍,無論項(xiàng)目最初使用哪種語言。這使得創(chuàng)建混合語言應(yīng)用程序和框架目標(biāo)就像創(chuàng)建用單一語言編寫的應(yīng)用程序或框架目標(biāo)一樣簡(jiǎn)單抬驴。

在混合語言目標(biāo)中使用Swift代碼中的Objective-C聲明的過程略有不同炼七,這取決于您是在編寫應(yīng)用程序還是框架。這兩個(gè)過程描述如下怎爵。

導(dǎo)入應(yīng)用程序目標(biāo)中的代碼

要將一組Objective-C文件導(dǎo)入到同一個(gè)app target中的Swift代碼中特石,需要依賴Objective-C橋接頭文件將這些文件暴露給Swift。當(dāng)您將Swift文件添加到現(xiàn)有的Objective-C應(yīng)用程序或?qū)bjective-C文件添加到現(xiàn)有的Swift應(yīng)用程序時(shí)鳖链,Xcode提供了創(chuàng)建這個(gè)頭文件的功能姆蘸。

如果接受,Xcode將創(chuàng)建橋接頭文件和正在創(chuàng)建的文件芙委,并使用產(chǎn)品模塊名后面跟著“-Bridging-Header.h”來命名它們逞敷。或者灌侣,您可以通過選擇?File > New > File > [operating system] > Source > Header File.推捐,自己創(chuàng)建一個(gè)橋接頭文件。

編輯橋接頭侧啼,將Objective-C代碼暴露給Swift代碼:

在Objective-C橋接頭中牛柒,導(dǎo)入你想要公開給Swift的每個(gè)Objective-C頭。

在構(gòu)建設(shè)置中痊乾,在Swift編譯器-代碼生成中皮壁,確保Objective-C橋接頭構(gòu)建設(shè)置有到橋接頭文件的路徑。路徑應(yīng)該與項(xiàng)目相關(guān)哪审,類似于信息的方式蛾魄。plist路徑在構(gòu)建設(shè)置中指定。在大多數(shù)情況下湿滓,您不需要修改這個(gè)設(shè)置滴须。

在框架目標(biāo)中導(dǎo)入代碼

要在與Swift代碼相同的框架目標(biāo)文件中使用Objective-C聲明,您需要將這些文件導(dǎo)入Objective-C傘形標(biāo)題——框架的主標(biāo)題叽奥。通過配置雨傘頭導(dǎo)入Objective-C文件:

在構(gòu)建設(shè)置中扔水,在打包中,確保將框架目標(biāo)的定義模塊設(shè)置設(shè)置為Yes而线。

在傘形標(biāo)頭中铭污,導(dǎo)入要公開給Swift的每個(gè)Objective-C標(biāo)頭恋日。

Swift看到你在傘頭中公開的每個(gè)標(biāo)題。該框架中的Objective-C文件的內(nèi)容可以從該框架目標(biāo)中的任何Swift文件中自動(dòng)獲得嘹狞,不需要導(dǎo)入語句岂膳。使用Objective-C代碼中的類和其他聲明,使用與系統(tǒng)類相同的Swift語法磅网。

將Swift導(dǎo)入Objective-C

從Objective-C代碼庫(kù)中訪問Swift類型和聲明谈截。



概述

通過導(dǎo)入xcode生成的頭文件,您可以在項(xiàng)目中的Objective-C代碼中使用Swift聲明的類型涧偷。這個(gè)文件是Objective-C的頭文件簸喂,它聲明目標(biāo)中的Swift接口,您可以將它看作是Swift代碼的傘形頭文件燎潮。您不需要做任何特殊的事情來創(chuàng)建生成的header—只需導(dǎo)入它來在Objective-C代碼中使用它的內(nèi)容喻鳄。

標(biāo)題的名稱是由您的產(chǎn)品模塊名稱生成的,后面跟著“-Swift.h”确封。默認(rèn)情況下除呵,此名稱與產(chǎn)品名稱相同,任何非字母數(shù)字字符都用下劃線(_)替換爪喘。如果名稱以數(shù)字開頭颜曾,則將第一個(gè)數(shù)字替換為下劃線。

將Swift聲明導(dǎo)入Objective-C代碼的過程略有不同秉剑,這取決于您是在編寫應(yīng)用程序還是框架泛豪。這兩個(gè)過程描述如下。

導(dǎo)入應(yīng)用程序目標(biāo)中的代碼

當(dāng)您構(gòu)建應(yīng)用程序目標(biāo)時(shí)侦鹏,您可以使用這種語法將您的Swift代碼導(dǎo)入到同一目標(biāo)內(nèi)的任何Objective-C .m文件中诡曙,并替換適當(dāng)?shù)拿Q:

#import"ProductModuleName-Swift.h"

默認(rèn)情況下,生成的頭文件包含使用public或open修飾符標(biāo)記的Swift聲明的接口略水。如果您的應(yīng)用程序目標(biāo)有一個(gè)Objective-C橋接頭岗仑,生成的頭還包括用內(nèi)部修飾符標(biāo)記的接口。標(biāo)記為private或fileprivate修飾符的聲明不會(huì)出現(xiàn)在生成的頭文件中聚请,也不會(huì)公開給Objective-C運(yùn)行時(shí),除非它們顯式地標(biāo)記為@IBAction稳其、@IBOutlet或@objc屬性驶赏。在單元測(cè)試目標(biāo)內(nèi)部,通過將@testable放在product module import語句前面既鞠,您可以訪問導(dǎo)入的內(nèi)部聲明煤傍,就好像它們是公共的一樣。

在框架目標(biāo)中導(dǎo)入代碼

要在與Objective-C代碼相同的框架目標(biāo)中導(dǎo)入一組Swift文件嘱蛋,請(qǐng)將您的Swift代碼的xcode生成的頭文件導(dǎo)入到您想要使用Swift代碼的任何Objective-C .m文件中蚯姆。

因?yàn)樯傻臉?biāo)頭是框架的公共接口的一部分五续,所以在為框架目標(biāo)生成的標(biāo)頭中只會(huì)出現(xiàn)標(biāo)記為public或open修飾符的聲明。用內(nèi)部修飾符標(biāo)記并在從Objective-C類繼承的類中聲明的方法和屬性可以被Objective-C運(yùn)行時(shí)訪問龄恋。但是疙驾,它們?cè)诰幾g時(shí)不可訪問,并且不會(huì)出現(xiàn)在框架目標(biāo)的生成頭文件中郭毕。

在相同的框架下它碎,將Swift代碼導(dǎo)入Objective-C:

在構(gòu)建設(shè)置中,在打包中显押,確保為該框架目標(biāo)定義的模塊設(shè)置設(shè)置為Yes扳肛。

使用這種語法并替換適當(dāng)?shù)拿Q,將Swift代碼從該框架目標(biāo)導(dǎo)入到該目標(biāo)中的任何Objective-C .m文件中:

#import <ProductName/ProductModuleName-Swift.h>

使用前向聲明在Objective-C標(biāo)頭中包含Swift類

當(dāng)Objective-C頭文件中的聲明引用來自同一目標(biāo)的Swift類或協(xié)議時(shí)乘碑,導(dǎo)入生成的頭將創(chuàng)建循環(huán)引用挖息。為了避免這種情況,使用Swift類或協(xié)議的前向聲明在Objective-C接口中引用它兽肤。

// MyObjcClass.h@classMySwiftClass;

@protocolMySwiftProtocol;

@interfaceMyObjcClass : NSObject

?(MySwiftClass *)returnSwiftClassInstance;

- (id)returnInstanceAdoptingSwiftProtocol;

// ...@end

Swift類和協(xié)議的前向聲明只能用作方法和屬性聲明的類型套腹。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市轿衔,隨后出現(xiàn)的幾起案子沉迹,更是在濱河造成了極大的恐慌,老刑警劉巖害驹,帶你破解...
    沈念sama閱讀 218,386評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件鞭呕,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡宛官,警方通過查閱死者的電腦和手機(jī)葫松,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,142評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來底洗,“玉大人腋么,你說我怎么就攤上這事『ヒ荆” “怎么了珊擂?”我有些...
    開封第一講書人閱讀 164,704評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)费变。 經(jīng)常有香客問我摧扇,道長(zhǎng),這世上最難降的妖魔是什么挚歧? 我笑而不...
    開封第一講書人閱讀 58,702評(píng)論 1 294
  • 正文 為了忘掉前任扛稽,我火速辦了婚禮,結(jié)果婚禮上滑负,老公的妹妹穿的比我還像新娘在张。我一直安慰自己用含,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,716評(píng)論 6 392
  • 文/花漫 我一把揭開白布帮匾。 她就那樣靜靜地躺著啄骇,像睡著了一般。 火紅的嫁衣襯著肌膚如雪辟狈。 梳的紋絲不亂的頭發(fā)上肠缔,一...
    開封第一講書人閱讀 51,573評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音哼转,去河邊找鬼明未。 笑死,一個(gè)胖子當(dāng)著我的面吹牛壹蔓,可吹牛的內(nèi)容都是我干的趟妥。 我是一名探鬼主播,決...
    沈念sama閱讀 40,314評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼佣蓉,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼披摄!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起勇凭,我...
    開封第一講書人閱讀 39,230評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤疚膊,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后虾标,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體寓盗,經(jīng)...
    沈念sama閱讀 45,680評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,873評(píng)論 3 336
  • 正文 我和宋清朗相戀三年璧函,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了傀蚌。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,991評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡蘸吓,死狀恐怖善炫,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情库继,我是刑警寧澤箩艺,帶...
    沈念sama閱讀 35,706評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站宪萄,受9級(jí)特大地震影響舅桩,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜雨膨,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,329評(píng)論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望读串。 院中可真熱鬧聊记,春花似錦撒妈、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,910評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至舆床,卻和暖如春棋蚌,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背挨队。 一陣腳步聲響...
    開封第一講書人閱讀 33,038評(píng)論 1 270
  • 我被黑心中介騙來泰國(guó)打工谷暮, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人盛垦。 一個(gè)月前我還...
    沈念sama閱讀 48,158評(píng)論 3 370
  • 正文 我出身青樓湿弦,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親腾夯。 傳聞我的和親對(duì)象是個(gè)殘疾皇子颊埃,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,941評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • Description Design and implement a data structure for Lea...
    Nancyberry閱讀 406評(píng)論 0 0
  • 人一直都是徘徊在感性與理性之間的動(dòng)物,可奇怪的是蝶俱,人在成長(zhǎng)的過程中總是先學(xué)習(xí)感性班利,而后學(xué)習(xí)理性。只有我一個(gè)人有這樣...
    烏木閱讀 990評(píng)論 0 1
  • 陰郁了一天的烏云籠罩著整個(gè)佛羅倫薩榨呆,夜里的雨淅淅瀝瀝罗标,紛紛攮攮的雨滴打得樹木枯皺的細(xì)枝隨風(fēng)搖曳。 街道的灰塵撲騰蕩...
    無糖熊噢閱讀 1,363評(píng)論 0 2
  • 我是一個(gè)女人愕提,今天要寫這篇文章估計(jì)要被女同胞們的口水淹死了馒稍!不過今天朋友圈、QQ說說浅侨、博客纽谒、微博上所曬出來的情人節(jié)...
    梁蘭芳閱讀 1,130評(píng)論 2 9
  • 期待已久的德清莫干山出游終于如期而至鼓黔。酷愛大自然的兒子不见,幾天前便早早收拾好行裝澳化,第一時(shí)間拿出自己的壓歲錢,積極...
    孫其花閱讀 330評(píng)論 1 0