在iOS混編項(xiàng)目中改造objc代碼

對(duì)objc代碼改造氛悬,適應(yīng)swift調(diào)用的同時(shí),也能提升objc代碼質(zhì)量

1.可選值

//在這兩個(gè)宏之間的都默認(rèn)是nonnull型
NS_ASSUME_NONNULL_BEGIN
NS_ASSUME_NONNULL_END
//如要指定某個(gè)屬性、返回值或者參數(shù)為可選值類型俄占,則可以單獨(dú)使用下面的關(guān)鍵字
nullable _Nullable

nullable、nonnull_Nullable淆衷、_Nonnull的區(qū)別
nullable缸榄、nonnull用在方法參數(shù)或者屬性的修飾
_Nullable、_Nonnull用在常量祝拯、任意指針的修飾
當(dāng)不確定是否會(huì)返回空值時(shí)甚带,可使用null_unspecified、_Null_unspecified修飾
ps.當(dāng)使用以上關(guān)鍵詞修飾后佳头,需特別注意編譯器拋出的警告??
例如一個(gè)使用nonnull修飾的NSString屬性鹰贵,返回了nil,此時(shí)編譯器會(huì)拋出警告康嘉,不影響編譯執(zhí)行砾莱,但在swift調(diào)用中,則會(huì)返回一個(gè)""空的字符串凄鼻,這可能就會(huì)導(dǎo)致類似 if string == "xx" else的條件語句結(jié)果與預(yù)期不一致腊瑟,導(dǎo)致邏輯錯(cuò)誤聚假。而如果是其它類型,則可能會(huì)導(dǎo)致閃退

2.枚舉闰非、常量膘格、宏

枚舉,首先要避免使用c的enum财松,改為使用NS_ENUMNS_OPTION瘪贱;然后使用NS_SWIFT_NAME適配swift規(guī)范

如下一個(gè)OC的枚舉

typedef NS_ENUM(NSUInteger, NotificationServiceType) {
    NotificationServiceTypeLocal,
    NotificationServiceTypeRemote
};

系統(tǒng)會(huì)自動(dòng)轉(zhuǎn)換為

public enum NotificationServiceType : UInt {
    case local = 0
    case remote = 1
}

如果要像UITableViewCellStyle轉(zhuǎn)換為UITableViewCell.Style則可使用NS_SWIFT_NAME(NotificationService.Type)

typedef NS_ENUM(NSUInteger, NotificationServiceType) {
    NotificationServiceTypeLocal,
    NotificationServiceTypeRemote
} NS_SWIFT_NAME(NotificationService.Type);
@interface NotificationService : UNNotificationServiceExtension
@end
extension NotificationService {
    public enum `Type` : UInt {
        case local = 0
        case remote = 1
    }
}
open class NotificationService : UNNotificationServiceExtension {
    open var type: NotificationService.`Type`
}

常量改造

字符串常量使用:NS_STRING_ENUM NS_EXTENSIBLE_STRING_ENUM
常數(shù)常量使用:NS_TYPED_ENUM NS_TYPED_EXTENSIBLE_ENUM
如下定義的字符串常量

FOUNDATION_EXTERN NSString *const NotificationServiceOptionTitle;
FOUNDATION_EXTERN NSString *const NotificationServiceOptionSubtitle;
FOUNDATION_EXTERN NSString *const NotificationServiceOptionBody;

如要更適用swift調(diào)用,則需做如下改造
1.首先上述的例子,在objc中也是不夠規(guī)范的,應(yīng)當(dāng)typedef NSString *const NotificationServiceOption;進(jìn)行類型聲明
2.使用NS_STRING_ENUM或者NS_EXTENSIBLE_STRING_ENUM修飾NotificationServiceOption
改造如下:

typedef NSString *const NotificationServiceOption NS_STRING_ENUM;
FOUNDATION_EXTERN NotificationServiceOption NotificationServiceOptionTitle;
FOUNDATION_EXTERN NotificationServiceOption NotificationServiceOptionSubtitle;
FOUNDATION_EXTERN NotificationServiceOption NotificationServiceOptionBody;

swift轉(zhuǎn)換如下

//NS_STRING_ENUM
public struct NotificationServiceOption : Hashable, Equatable, RawRepresentable {
    public init(rawValue: String)
}
extension NotificationServiceOption {
    public static let title: NotificationServiceOption
    public static let subtitle: NotificationServiceOption
    public static let body: NotificationServiceOption
}

NS_STRING_ENUMNS_EXTENSIBLE_STRING_ENUM的區(qū)別在于柠新,NS_EXTENSIBLE_STRING_ENUM在swift中可擴(kuò)展

宏定義

swift無法完全識(shí)別objc中的宏定義贷笛,對(duì)于單個(gè)變量的宏定義用狱,如字符串、常數(shù)等,swift會(huì)識(shí)別為常量
#define NotificationServiceToken @"abcdefg"會(huì)被識(shí)別為public var NotificationServiceToken: String { get }
而一些復(fù)雜的表達(dá)式主慰,方法宏則無法被swift識(shí)別

3.錯(cuò)誤處理

使用NS_ERROR_ENUM定義error枚舉
SDWebImage中的做法為例

FOUNDATION_EXPORT NSErrorDomain const _Nonnull SDWebImageErrorDomain;
typedef NS_ERROR_ENUM(SDWebImageErrorDomain, SDWebImageError) {
    SDWebImageErrorInvalidURL = 1000, 
    SDWebImageErrorBadImageData = 1001,
};

會(huì)被swift識(shí)別為

public let SDWebImageErrorDomain: String
public struct SDWebImageError {
    public init(_nsError: NSError)
    public static var errorDomain: String { get }
    public enum Code : Int {
        public typealias _ErrorType = SDWebImageError
        case invalidURL = 1000
        case badImageData = 1001 
    }
    public static var invalidURL: SDWebImageError.Code { get }
    public static var badImageData: SDWebImageError.Code { get }
}

這樣就可以像swift原生一樣,使用SDWebImageError處理異常

func testSDWebImageError() {
    do {
        let url = try testThrowSDError(path: "")
    } catch let error as SDWebImageError {
        switch error.code {
        case .invalidURL:
            // do something
            print("invalidURL")
            break
        default: break
        }
    } catch {
    }
}
func testThrowSDError(path: String?) throws -> URL {
    if let path = path, !path.isEmpty, let url = URL(string: path) {
        return url
    } else {
        throw SDWebImageError(.invalidURL)
    }
}

4.api命名 NS_SWIFT_NAME

通常swift識(shí)別的objc方法鲫售,會(huì)根據(jù)返回值類型共螺、方法名、參數(shù)類型情竹、參數(shù)名等語義識(shí)別出恰當(dāng)?shù)膕wift函數(shù)名藐不、參數(shù)標(biāo)簽、參數(shù)名等秦效,但有時(shí)并不能完全符合開發(fā)者的期望雏蛮,此時(shí)可NS_SWIFT_NAME手動(dòng)聲明swift轉(zhuǎn)換的函數(shù)名

5.構(gòu)造器

NS_DESIGNATED_INITIALIZER,NS_UNAVAILABLE

6.第三方庫的引用

1.CocoaPods引用OC庫,在pod路徑后添加:modular_headers => true參數(shù)
2....

7.使用objc泛型

//bad
@property (strong) NSArray *array;
@property (strong) NSDictionary *dictionary;
//good
@property (strong) NSArray<NSString *> *genericArray;
@property (strong) NSDictionary<NSString *, NSString *> *genericDictionary;

//bad
open var array: [Any]
open var dictionary: [AnyHashable : Any]
//good
open var genericArray: [String]
open var genericDictionary: [String : String]

最后棉安,值得一提的是底扳,以上改造不僅僅便于swift調(diào)用铸抑,也能提升objc的代碼質(zhì)量和規(guī)范贡耽。同時(shí)從swift的角度去思考o(jì)bjc代碼,也能加深對(duì)objc結(jié)構(gòu)的理解鹊汛。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末蒲赂,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子刁憋,更是在濱河造成了極大的恐慌滥嘴,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,734評(píng)論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件至耻,死亡現(xiàn)場(chǎng)離奇詭異若皱,居然都是意外死亡镊叁,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,931評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門走触,熙熙樓的掌柜王于貴愁眉苦臉地迎上來晦譬,“玉大人,你說我怎么就攤上這事互广×搽纾” “怎么了?”我有些...
    開封第一講書人閱讀 164,133評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵惫皱,是天一觀的道長(zhǎng)像樊。 經(jīng)常有香客問我,道長(zhǎng)旅敷,這世上最難降的妖魔是什么生棍? 我笑而不...
    開封第一講書人閱讀 58,532評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮扫皱,結(jié)果婚禮上足绅,老公的妹妹穿的比我還像新娘。我一直安慰自己韩脑,他們只是感情好氢妈,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,585評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著段多,像睡著了一般首量。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上进苍,一...
    開封第一講書人閱讀 51,462評(píng)論 1 302
  • 那天加缘,我揣著相機(jī)與錄音,去河邊找鬼觉啊。 笑死拣宏,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的杠人。 我是一名探鬼主播勋乾,決...
    沈念sama閱讀 40,262評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼嗡善!你這毒婦竟也來了辑莫?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,153評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤罩引,失蹤者是張志新(化名)和其女友劉穎各吨,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體袁铐,經(jīng)...
    沈念sama閱讀 45,587評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡揭蜒,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,792評(píng)論 3 336
  • 正文 我和宋清朗相戀三年横浑,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片屉更。...
    茶點(diǎn)故事閱讀 39,919評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡伪嫁,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出偶垮,到底是詐尸還是另有隱情张咳,我是刑警寧澤,帶...
    沈念sama閱讀 35,635評(píng)論 5 345
  • 正文 年R本政府宣布似舵,位于F島的核電站脚猾,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏砚哗。R本人自食惡果不足惜龙助,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,237評(píng)論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望蛛芥。 院中可真熱鬧提鸟,春花似錦、人聲如沸仅淑。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,855評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽涯竟。三九已至赡鲜,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間庐船,已是汗流浹背银酬。 一陣腳步聲響...
    開封第一講書人閱讀 32,983評(píng)論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留筐钟,地道東北人揩瞪。 一個(gè)月前我還...
    沈念sama閱讀 48,048評(píng)論 3 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像篓冲,于是被迫代替她去往敵國和親李破。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,864評(píng)論 2 354

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

  • C語言相關(guān)面試題 1.static有什么用途纹因? 答案:在C語言中喷屋,static主要定義全局靜態(tài)變量琳拨,定義局部靜態(tài)變...
    Leeson1989閱讀 2,237評(píng)論 0 20
  • 前言 通過閱讀別人的優(yōu)秀源碼瞭恰,你會(huì)發(fā)現(xiàn)別人的開源API設(shè)計(jì)中,有一些宏你是經(jīng)常忽略的狱庇,或者你不知道的惊畏。通過這些宏恶耽,...
    gitKong閱讀 5,166評(píng)論 5 41
  • 翻譯自蘋果官方文檔 和Objective-C交互 互用性是指,在Swift和Objective-C之間可以建立一個(gè)...
    桔子聽閱讀 10,213評(píng)論 0 34
  • 章節(jié)導(dǎo)航:Swift開發(fā)指南:使用Swift與Cocoa和Objective-C(Swift 4) - 1.入門S...
    Minecode閱讀 3,191評(píng)論 0 23
  • C語言相關(guān)面試題 1.static有什么用途颜启? 答案:在C語言中偷俭,static主要定義全局靜態(tài)變量,定義局部靜態(tài)變...
    ios南方閱讀 6,799評(píng)論 1 18