最近在嘗試oc和swift的混編,一是:swift是大勢所趨,終究是要學習的。二是:項目目前架構是oc架構,全部重構為swift也不現(xiàn)實。下面是混編中遇到的一些問題和總結:
1.在oc項目中第一次創(chuàng)建swift文件的時候,會彈框提示是否要創(chuàng)建橋接文件。當然要創(chuàng)建了,否則還要自己動手創(chuàng)建和配置。教程網(wǎng)上很多,就不重復了。
2.oc的代碼中需要調用swift的文件,需要導入隱式頭文件:xxx-Swift.h,xxx-Swift.h在項目中是看不到的,但是確實是可以import的
//xxx是你的項目名字(一般是target的名字)
#import "xxx-Swift.h"
//然后代碼如下:Ps:DYUserInfoSwiftVC是新建的swift的類。其實在oc的代碼中引用swift的類,代碼風格是和oc保持一致。swift的代碼中引用oc的類,代碼風格和swift保持一致。
//oc中引用swift(DYUserInfoSwiftVC是swift的類)
DYUserInfoSwiftVC *userSetSwift = [[DYUserInfoSwiftVC alloc] init];
[weakSelf pushController:userSetSwift];
//swift引用oc(DYSettingMesssageSetVC是oc的類)
let messageSet:DYSettingMesssageSetVC = DYSettingMesssageSetVC.init()
self.navigationController?.pushViewController(messageSet, animated: true)
3.swift中引用oc的類,需要在橋接文件 “項目名稱-Bridging-Header.h”中 import 用到的oc文件,不需要在swift類中引用橋接文件。swift引用swift類也不需要導入頭文件,因為編譯器幫我們處理了,直接用就可以了。如圖:
4.相關配置信息:
5.下面說下我的項目中遇到的問題:
(1)我們的項目是多target管理的,有多個pch文件,pch文件有一些宏定義,管理上架版本和企業(yè)版本,代碼中有一些根據(jù)宏定義的判斷。
EF87EB72-6194-4698-A01F-1360A965F49D.png
oc代碼中直接if(DY_APPSTORE)就可以做相應的邏輯處理了,然而swift中卻不行,必須if(DY_APPSTORE == 0)這種形式進行判斷。
if (0 == DY_APPSTORE) {
//代碼
}
(2)oc中引用swifit時需要導入隱式頭文件:xxx-Swift.h,但是如果項目是多個target的話,會生成多個xxx-Swift.h隱式文件。所以需要進行判斷區(qū)分,否則會提示某個xxx-Swift.h找不到。處理方式如下:
新建一個Swift.h文件,代碼如下。只需要在需要引入swift的代碼中導入Swift.h文件即可。
8769B25A-2056-4BCB-8709-5F743F7C9097.png
(3)oc中經(jīng)常用#pragma mark - 來添加注解,swift中需要用://MARK:-lazy這種形式。
(4)swift中的宏定義和oc的有區(qū)別。oc中可以宏定義一個方法,方便直接調用,swift不能這么寫,如:
//oc
#define DYGetColorFromHex(rgbValue) [UIColor colorWithRed:((float)((rgbValue & 0xFF0000) >> 16))/255.0 green:((float)((rgbValue & 0xFF00) >> 8))/255.0 blue:((float)(rgbValue & 0xFF))/255.0 alpha:1.0]
在swift如何定義宏定義呢,可以新建一個DYSwiftDefine.swift的文件,直接寫相應的函數(shù)方法就可以了,代碼如下:
import Foundation
//顏色值
func UIColorFromRGB(rgbValue: UInt) -> UIColor {
return UIColor(
red: CGFloat((rgbValue & 0xFF0000) >> 16) / 255.0,
green: CGFloat((rgbValue & 0x00FF00) >> 8) / 255.0,
blue: CGFloat(rgbValue & 0x0000FF) / 255.0,
alpha: CGFloat(1.0)
)
}
因為新建的DYSwiftDefine.swift文件不需要在swift文件中導入的,是可以直接在代碼中調用的:
self.view.backgroundColor = UIColorFromRGB(rgbValue: 0xffffff);
(5)oc中調用swift方法和傳值時遇到的坑:
上面講到在oc中調用swift,只需要導入隱式頭文件:xxx-Swift.h即可。這種方式是可以創(chuàng)建controller然后進行push操作,但是如果想調用swift類中的方法或者給block賦值就會報錯。處理方式如下:
import UIKit
typealias DYMusicModelBlock = (_ model:DYMusicListModelSwift)->Void
@objcMembers class DYMusicListVCSwift: BaseViewController,UITableViewDelegate,UITableViewDataSource,DevPulldownRefreshDelegate,LSLoadMoreViewDelegate,DYInputOfSearchViewDelegate {
//MARK:全局變量
public var musicModelBlock:DYMusicModelBlock?
}
是不是注意到了“@objcMembers”
@objcMembers 在Swift 4中繼承 NSObject 的 swift class 不再默認全部 bridge 到 OC,如果我們想要使用的話我們就需要在class前面加上@objcMembers 這么一個關鍵字。
然后就可以復制和使用相關的方法了
DYMusicListVCSwift *music = [[DYMusicListVCSwift alloc] init];
music.musicModelBlock = ^(DYMusicListModelSwift * model) {
weakSelf.musicArray = [NSMutableArray arrayWithObjects:DevNSStringFilterEmptyString(model.musicIcon), DevNSStringFilterEmptyString(model.musicName), DevNSStringFilterEmptyString(model.musicUrl), DevNSStringFilterEmptyString(model.musicTime), DevNSStringFilterEmptyString(model.musicAuthor), DevNSStringFilterEmptyString(model.musicId), nil];
weakSelf.actualValueTextField.text = model.musicName;
};
[self.navigationController pushViewController:music animated:YES];
(6) swift中的代碼強轉:有時候我們需要對一些id類型的對象進行強轉成我們需要的對象。
//假設需要解析一個請求回調的block的數(shù)據(jù)
self.musicListSearchRequest.successBlock = {(response) in
if let resultCode = responseDic["resultCode"] as? String{
//是string類型
}else{
//不是string類型,可能是服務器返回的數(shù)據(jù)類型和約定的不一樣,或者你不能用String強轉,因為返回的是Int類型。
}
主要就是 if let xxxx = xxxx["xxx"] as? xxxx{
}else{
}
做一個類型轉換的判斷。如果不判斷,直接強轉后直接用的話有可能crash,比如你認為強轉后是String類型,其實是個Int類型。你調用string的方法isEmpty()的時候就crash。