[Swift5.1] 24-OC與Swift 混編

MARK叠萍、TODO戈钢、FIXME

// MARK: 類似于OC中的 #pragma mark
// MARK: - 類似于OC中的 #pragma mark -
// TODO: 用于標(biāo)記未完成的任務(wù)
// FIXME: 用于標(biāo)記待修復(fù)的問題

補(bǔ)充:

  • 使用#warning("undo") 標(biāo)記未做的事情
  • 定義有返回值函數(shù), 如果沒寫完可以用fatalError()占位
func test() -> Int {
    #warning("undo")
    fatalError()
}

條件編譯

// 操作系統(tǒng):macOS\iOS\tvOS\watchOS\Linux\Android\Windows\FreeBSD
#if os(macOS) || os(iOS)
// CPU 架 構(gòu) :i386\x86_64\arm\arm64
#elseif arch(x86_64) || arch(arm64)
// swift版本
#elseif swift(<5) && swift(>=3)
// 模擬器
#elseif targetEnvironment(simulator)
// 可以導(dǎo)入某模塊
#elseif canImport(Foundation)  #else
#endif
#if DEBUG
// debug模式
#else
// release模式 
#endif
#if TEST
print("test")
#endif

#if OTHER
print("other")
#endif

打印

func log<T>(_ msg: T,
            file: NSString = #file,
            line: Int = #line,
            fn: String = #function) {
    #if DEBUG
    let prefix = "\(file.lastPathComponent)_\(line)_\(fn):"
    print(prefix, msg)
    #endif
}

系統(tǒng)版本檢測

if #available(iOS 10, macOS 10.12, *) {
    // 對于iOS平臺试溯,只在iOS10及以上版本執(zhí)行
    // 對于macOS平臺的畴,只在macOS 10.12及以上版本執(zhí)行
    // 最后的*表示在其他所有平臺都執(zhí)行
}

API可用性說明

@available(iOS 10, macOS 10.15, *)
class Person {}

struct Student {
    @available(*, unavailable, renamed: "study")
    func study_() {}
    func study() {}
    
    @available(iOS, deprecated: 11)
    @available(macOS, deprecated: 10.12)
    func run() {}
}

更多用法參考:https://docs.swift.org/swift-book/ReferenceManual/Attributes.html

iOS程序的入口

  • 在AppDelegate上面默認(rèn)有個(gè)@UIApplicationMain標(biāo)記,這表示
    編譯器自動生成入口代碼(main函數(shù)代碼)节仿,自動設(shè)置AppDelegate為APP的代理

  • 也可以刪掉@UIApplicationMain,自定義入口代碼:新建一個(gè)main.swift文件

//  main.swift
//  TestDemo
import UIKit

class MyApplication: UIApplication {}

UIApplicationMain(CommandLine.argc,
                  CommandLine.unsafeArgv, NSStringFromClass(MyApplication.self), NSStringFromClass(AppDelegate.self))

Swift調(diào)用OC

  • 1> 新建1個(gè)橋接頭文件掉蔬,文件名格式默認(rèn)為:{targetName}-Bridging-Header.h
  • 如果直接創(chuàng)建OC類文件, 會提示(如下圖)并自動創(chuàng)建 {targetName}-Bridging-Header.h文件
  • 2> 在 {targetName}-Bridging-Header.h 文件中 #import OC需要暴露給Swift的內(nèi)容
#import "Person.h"

Swift調(diào)用OC

  • 1> Person.h 代碼
int sum(int a, int b);

@interface Person : NSObject
@property (nonatomic, assign) NSInteger age;
@property (nonatomic, copy) NSString *name;

- (instancetype)initWithAge:(NSInteger)age name:(NSString *)name;
+ (instancetype)personWithAge:(NSInteger)age name:(NSString *)name;

- (void)run;
+ (void)run;

- (void)eat:(NSString *)food other:(NSString *)other;
+ (void)eat:(NSString *)food other:(NSString *)other;
@end
  • 2> Person.m 代碼
@implementation Person
- (instancetype)initWithAge:(NSInteger)age name:(NSString *)name {
    if (self = [super init]) {
        self.age = age;
        self.name = name;
    }
    return self;
}
+ (instancetype)personWithAge:(NSInteger)age name:(NSString *)name {
    return [[self alloc] initWithAge:age name:name];
}

+ (void)run { NSLog(@"Person +run"); }
-  (void)run { NSLog(@"%zd %@ -run", _age, _name); }

+ (void)eat:(NSString *)food other:(NSString *)other {
    NSLog(@"Person +eat %@ %@", food, other);
}
- (void)eat:(NSString *)food other:(NSString *)other {
    NSLog(@"%zd %@-eat %@ %@", _age, _name, food, other);
}
@end

int sum(int a, int b) { return a + b; }
  • 3> main.swift 中 swift代碼
var p = Person(age: 10, name: "Jack")
p.age = 18
p.name = "Rose"
p.run() // 18 Rose -run
p.eat("Apple", other: "Water") // 18 Rose -eat Apple Water

Person.run() // Person +run
Person.eat("Pizza", other: "Banana") // Person +eat Pizza Banana

print(sum(10, 20)) // 30

Swift調(diào)用OC – @_silgen_name

應(yīng)用場景1:

  • 如果C語言暴露給Swift的函數(shù)名跟Swift中的其他函數(shù)名沖突了
  • 可以在Swift中使用 @_silgen_name 修改C函數(shù)名
// C語言
int sum(int a, int b) {
    return a + b;
}
// Swift  
@_silgen_name("sum") func swift_sum(_ v1: Int32, _ v2: Int32) -> Int32
// C語言函數(shù)名, 重命名函數(shù) swift_sum
print(swift_sum(10, 20)) // 30
print(sum(10, 20)) // 30

應(yīng)用場景2:
_silgen_name可以將系統(tǒng)私有函數(shù)重命名后使用.

OC調(diào)用Swift

  • Xcode已經(jīng)默認(rèn)生成一個(gè)用于OC調(diào)用Swift的頭文件廊宪,文件名格式是: {targetName}-Swift.h
  • OC項(xiàng)目中如果直接創(chuàng)建swift類文件, 會提示(如下圖)并自動創(chuàng)建 {targetName}-Bridging-Header.h文件
  • 1> Car.swift 文件
import Foundation

@objcMembers class Car: NSObject {
    var price: Double
    var band: String
    init(price: Double, band: String) {
        self.price = price
        self.band = band
    }
    func run() { print(price, band, "run") }
    static func run() { print("Car run") }
}

extension Car {
    func test() { print(price, band, "test") }
}
  • 2> Swift暴露給OC的類最終繼承自NSObject
  • 3> 使用@objc修飾需要暴露給OC的成員
  • 4> 使用@objcMembers修飾類
    代表默認(rèn)所有成員都會暴露給OC(包括擴(kuò)展中定義的成員)
    最終是否成功暴露,還需要考慮成員自身的訪問級別
  • 6> OC代碼
    OC文件中導(dǎo)入#import "Test-Swift.h"
#import "Test-Swift.h"
int sum(int a, int b) {
    Car *c = [[Car alloc] initWithPrice:10.5 band:@"BMW"];
    c.band = @"Bently";
    c.price = 108.5;
    [c run]; // 108.5 Bently run  [c test]; // 108.5 Bently test  [Car run]; // Car run
    return a + b;
}

OC調(diào)用Swift – @objc

可以通過 @objc 重命名Swift暴露給OC的符號名(類名眉踱、屬性名挤忙、函數(shù)名等)

@objc(Car)
@objcMembers class Car: NSObject {
    var price: Double
    @objc(name)
    var band: String
    init(price: Double, band: String) {
        self.price = price
        self.band = band
    }
    @objc(drive)
    func run() { print(price, band, "run") }
    static func run() { print("Car run") }
}
extension Car {  @objc(exec:v2:)
    func test() { print(price, band, "test") }
}
Car *c = [[Car alloc] initWithPrice:10.5 band:@"BMW"];
c.name = @"Bently";
c.price = 108.5;
[c drive]; // 108.5 Bently run
[c exec:10 v2:20]; // 108.5 Bently test
[Car run]; // Car run

思考:
1.為什么Swfit暴露給OC類最終要繼承自NSObject?
答:
OC依賴于runtime機(jī)制,runtime要求類有isa指針, 使用消息傳遞機(jī)制就需要繼承自NSObject

2.p.run()底層是怎么調(diào)用的?反過來,OC調(diào)用Swift底層又是如何調(diào)用?
答:運(yùn)行runtime機(jī)制, 執(zhí)行obj_msgSend

3.car.run()底層是怎么調(diào)用的?
答:
swift中, 調(diào)用暴露給OC類的方法,使用虛表.
如果實(shí)在要用OC的runtime機(jī)制, 可以在方法前加dynamic關(guān)鍵字.

選擇器(Selector)

  • Swift中依然可以使用選擇器,使用#selector(name)定義一個(gè)選擇器
  • 必須是被@objcMembers@objc修飾的方法才可以定義選擇器
@objcMembers class Person: NSObject {
    func test1(v1: Int) { print("test1") }
    func test2(v1: Int, v2: Int) { print("test2(v1:v2:)") }
    func test2(_ v1: Double, _ v2: Double) { print("test2(_:_:)") }
    func run() {
        perform(#selector(test1))
        perform(#selector(test1(v1:)))
        perform(#selector(test2(v1:v2:)))
        perform(#selector(test2(_:_:)))
        perform(#selector(test2 as (Double, Double) -> Void))
    }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
禁止轉(zhuǎn)載谈喳,如需轉(zhuǎn)載請通過簡信或評論聯(lián)系作者。
  • 序言:七十年代末戈泼,一起剝皮案震驚了整個(gè)濱河市婿禽,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌大猛,老刑警劉巖扭倾,帶你破解...
    沈念sama閱讀 212,599評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異挽绩,居然都是意外死亡膛壹,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,629評論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來模聋,“玉大人肩民,你說我怎么就攤上這事×捶剑” “怎么了持痰?”我有些...
    開封第一講書人閱讀 158,084評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長祟蚀。 經(jīng)常有香客問我工窍,道長,這世上最難降的妖魔是什么前酿? 我笑而不...
    開封第一講書人閱讀 56,708評論 1 284
  • 正文 為了忘掉前任患雏,我火速辦了婚禮,結(jié)果婚禮上罢维,老公的妹妹穿的比我還像新娘淹仑。我一直安慰自己,他們只是感情好言津,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,813評論 6 386
  • 文/花漫 我一把揭開白布攻人。 她就那樣靜靜地躺著,像睡著了一般悬槽。 火紅的嫁衣襯著肌膚如雪怀吻。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 50,021評論 1 291
  • 那天初婆,我揣著相機(jī)與錄音蓬坡,去河邊找鬼。 笑死磅叛,一個(gè)胖子當(dāng)著我的面吹牛屑咳,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播弊琴,決...
    沈念sama閱讀 39,120評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼兆龙,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了敲董?” 一聲冷哼從身側(cè)響起紫皇,我...
    開封第一講書人閱讀 37,866評論 0 268
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎腋寨,沒想到半個(gè)月后聪铺,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,308評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡萄窜,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,633評論 2 327
  • 正文 我和宋清朗相戀三年铃剔,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了撒桨。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,768評論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡键兜,死狀恐怖凤类,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情蝶押,我是刑警寧澤踱蠢,帶...
    沈念sama閱讀 34,461評論 4 333
  • 正文 年R本政府宣布,位于F島的核電站棋电,受9級特大地震影響茎截,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜赶盔,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,094評論 3 317
  • 文/蒙蒙 一企锌、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧于未,春花似錦撕攒、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,850評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至闷叉,卻和暖如春擦俐,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背握侧。 一陣腳步聲響...
    開封第一講書人閱讀 32,082評論 1 267
  • 我被黑心中介騙來泰國打工蚯瞧, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人品擎。 一個(gè)月前我還...
    沈念sama閱讀 46,571評論 2 362
  • 正文 我出身青樓埋合,卻偏偏與公主長得像,于是被迫代替她去往敵國和親萄传。 傳聞我的和親對象是個(gè)殘疾皇子甚颂,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,666評論 2 350