前言:
swift3.0出來后, 可以看到改變很大, 和cocoa, Foundation...的交互也變得更方便了, 同時swift編寫的應用適配到iOS7, 所以, 我們可以相信: 在未來使用swift的情況會逐漸增加了, 同時會涉及到oc和swift在項目中并存的情況, 這里我重新讀了官方的'Using swift with Cocoa and Objective-C(swift3)'的文檔, 記錄了一些個人覺得比較常用的筆記, 請大家選擇性閱讀(里面的代碼 均來自文檔)
- oc的初始化方法在swift中被引為
init(...) --- 如果初始化不會失敗
init?(...) --- 如果初始化可能失敗
init!(...) --- 否則
- oc中的property里的(getter==, setter==)將會被swift忽略
- id對應Anyobject 但是所有的Anyobject在swift中是可選值, 如果之前的值為可選值, 在被設置為Anyobject后就是多重可選值了
- oc中的屬性被標記為
nullable -> 在swift中相當于 ?
nonnull -> 在swift中相當于 非可選屬性
未標記 -> 在swift中相當于 ! - oc中的輕量級泛型也是對應與swift中的泛型
@property NSArray<NSDate *> *dates
對應于 var dates: [Date] - swift 中的閉包默認捕獲變量的方式相當于 oc中block中捕獲被標記為 __block的變量方式 -> 就是說 閉包捕獲到的是變量的指針
- swift中只要不是在多線程中, 建議使用[unowned self]來避免循環引用, 多線程中, 建議使用[weak self]
- == 操作符相當于oc中的isEqual: --- 即比較內容是否相等
=== 相當于oc中的指針比較 - 繼承自NSObject的子類如果重寫了isEquals: 方法, 應當提供 hash 這個屬性
- 不能在oc中繼承swift的class
- 如果在swift中遇到oc中不支持的命名 可以利用 @objc(name)為他(屬性 枚舉, 方法名...)名個別名
- @nonobjc 用來標記oc中不支持的
- dynamic 將屬性或者方法標記為dynamic就是告訴編譯器把它當作oc里的屬性或方法來使用(runtime),
當需要使用 KVO 或者 runtime的時候需要這樣處理 - 當使用oc的 perform(selector, with:)方法的時候 會返回一個可選值(指向AnyObject的指針)
但是使用perform(:on:with:waitUntilDone:modes:) and perform(:with:afterDelay:)不會返回可選值 - 使用 #keyPath() 可以轉換為string, #keyPath(class.property) == "property"
可用于KVC 例如person.value(forKey: #keyPath(Person.name)) = person.name
但是測試了下不能修改swift中的只讀屬性 不知道有什么方便的用處 - NSClassFromString("MyFramework.MyClass")
- @IBDesignable 用在class(UIView的子類)聲明的前面, 然后就可以在storyBoard中的inspector編輯它
@IBInspectable 用在(UIView的子類)的屬性前面, 然后就可以在storyBoard中的inspector編輯它 ,就想系統提供的可以設置顏色,字體... - swift中的屬性默認是strong類型, 只有可選類型才能被標記為weak
oc中的 copy屬性 轉換為swift中的@NSCopying 必須遵守NSCoding協議 - 使用Core Data的時候所有的屬性和方法需要標記為 @NSManaged
- 文檔中指出"The corresponding reference types can be accessed with their original NS class name prefix."
但是beta版本中不能很好的使用NS開頭的 - 在oc和swift的橋接類型之間 直接使用 as 可以相互轉換
- 因為swift中的String和NSString使用的編碼方式不一樣,
所以在swift中要對string使用索引的時候 不能直接使用 Int 或者NSRange
需要使用String.Index and Range<String.Index> - swift會將Double, Int, Bool, Uint, Float和NSNumber橋接, 所以可以直接將
這些類型的值使用 as NSNumber轉換為NSNumber, 但是逆向進行是得到的可選值 as? - Foundation 和Core Foundation 之間的類型有toll-free bridge('免費橋')
- Foundation中的常量, 在swift中被換為類嵌套的枚舉
NSJSONReadingOptions ----- >> JSONSerialization.ReadingOption - swift中使用 Core Foundation
- 如果使用swift處理過的函數不用我們手動管理內存分配
- 否則需要我們處理
- 區分的方式: 當返回值是 Unmanaged<Instance>的時候說明需要我們處理
- 處理方法: 在使用返回的值之前調用他對應的takeUnretainedValue() 或
takeRetainedValue()即可 - 例如let memoryManagedResult = StringByAddingTwoStrings(str1, str2).takeUnretainedValue()
- swift中Core Foundation里的類型 Ref后綴被去掉了 例如 CFTypeRef -> CFType
- 在oc的方法 使用 NS_SWIFT_NOTHROW , 將不會使用swift的異常拋出機制
- swift中直接使用 is 來實現oc中isKindOfClass: 的功能
- swift中使用kvo的條件: 1.必須繼承自NSObject 2. 被觀察的屬性 要被標記為 dynamic
- swift 中的單例很簡單:
class Singleton {
static let sharedInstance = Singleton()
}
或者
class Singleton {
static let sharedInstance: Singleton = {
let instance = Singleton()
// setup code
return instance
}()
}
- swift和C的交互: c的函數在swift中均為全局函數
- 使用CF_SWIFT_NAME 這個宏可以將c中的屬性或者函數轉換為swift中
eg:
Color ColorCreateWithCMYK(float c, float m, float y, float k) CF_SWIFT_NAME(Color.init(c:m:y:k:));
對應為swift中
extension Color {
init(c: Float, m: Float, y: Float, k: Float)
}
- c語言中的枚舉 如果使用了NS_ENUM定義, 則在swift中被處理為對應的枚舉
如果沒有使用NS_ENUM定義, 則被處理為結構體
typedef NS_ENUM(NSInteger, UITableViewCellStyle) {
UITableViewCellStyleDefault,
UITableViewCellStyleValue1,
UITableViewCellStyleValue2,
UITableViewCellStyleSubtitle
};
//對應與
enum UITableViewCellStyle: Int {
case `default`
case value1
case value2
case subtitle
}
typedef enum {
MessageDispositionUnread = 0,
MessageDispositionRead = 1,
MessageDispositionDeleted = -1,
} MessageDisposition;
對應與
struct MessageDisposition: RawRepresentable, Equatable {}
var MessageDispositionUnread: MessageDisposition { get }
var MessageDispositionRead: MessageDisposition { get }
var MessageDispositionDeleted: MessageDisposition { get }
- c中的被NS_OPTIONS修飾的枚舉, 在swift中是OptionSet類型, -> 即可以使用數組方式選多個值
typedef NS_OPTIONS(NSUInteger, UIViewAutoresizing) {
UIViewAutoresizingNone = 0,
UIViewAutoresizingFlexibleLeftMargin = 1 << 0,
UIViewAutoresizingFlexibleWidth = 1 << 1,
UIViewAutoresizingFlexibleRightMargin = 1 << 2,
UIViewAutoresizingFlexibleTopMargin = 1 << 3,
UIViewAutoresizingFlexibleHeight = 1 << 4,
UIViewAutoresizingFlexibleBottomMargin = 1 << 5
};
對應與
public struct UIViewAutoresizing : OptionSet {
public init(rawValue: UInt)
public static var flexibleLeftMargin: UIViewAutoresizing { get }
public static var flexibleWidth: UIViewAutoresizing { get }
public static var flexibleRightMargin: UIViewAutoresizing { get }
public static var flexibleTopMargin: UIViewAutoresizing { get }
public static var flexibleHeight: UIViewAutoresizing { get }
public static var flexibleBottomMargin: UIViewAutoresizing { get }
}
在swift中直接使用 let resize = [. flexibleLeftMargin, . flexibleWidth...]
- 在swift中全局變量和存儲屬性都被保證只初始化一次,
- 所以用來當作OC里面的#define定義的常量
- 同時swift全局函數可以當作OC里#define定義的復雜宏(類似函數)
- swift中的條件編譯 自定義編譯符的方法(例如: DEBUG_LOGGING)
- 首先在project 的設置里面設置swift -D DEBUG_LOGGING to set the DEBUG_LOGGING
- 然后使用 #if DEBUG_LOGGING // 操作 #endif
#if arch(arm) || arch(arm64)
#if swift(>=3.0)
print("Using Swift 3 ARM code")
#else
print("Using Swift 2.2 ARM code")
#endif
#elseif arch(x86_64)
print("Using 64-bit x86 code.)
#else
print("Using general code.")
#endif
- swift中使用指針的方式
- 使用inout方式 &變量
- 使用UnsafePointer<Type> 或者UnsafeMutablePointer<Type>
例如這個函數接受的參數可以傳許多種
let x: Float = 0
func takesAPointer(_ p: UnsafePointer<Float>!) {
// ...
}
takesAPointer(&x)
takesAPointer([0.0,1.0])
- 在swift中申明oc中的包含可選實現方法的協議時需要在協議和方法前都標記objc
@objc public protocol MySwiftProtocol {
// 必須實現
func requiredMethod()
@objc optional func optionalMethod()
}
- 將oc的方法或者屬性使用NS_SWIFT_NAME()可以為他們在swift中命一個別名
- 將oc的方法或使用 NS_SWIFT_UNAVAILABLE()可以讓他在swift中不可用