1.Swift相對與OC一些更好用的特性
(1)更好用的switch...case,for循環,枚舉,結構體
a. switch...case
不需要break,一個case可以寫多個條件,使用fallthrough繼續執行
let num = arc4random() % 10
switch num {
case 1, 2:
print("1, 2")
case 3..<5:
print("3, 4")
case ..<7:
print("6")
case ...8:
print("8")
default:
print("defalut")
}
基本數據類型都能判斷,并且能使用where語句
let testArray = [1,2,3]
switch testArray {
case let array1 where array1.first == 1:
print(array1.first!)
default:
print(testArray)
}
b. for循環
普通for循環
for i in 0..<8 {
}
for i in 0..<8 where i % 2 == 0 {
}
for i in (0..<8).reversed() {
}
for i in stride(from: 0, to: 8, by: 2) {
}
for i in stride(from: 0, through: 8, by: 2) {
}
集合類型的遍歷
// 數組遍歷
var array = [1,2,3,4]
for item in array {
}
for (i, item) in array.enumerated() {
}
for item in array {
array.append(item)
}
// 數組的函數式
let mapArray = array.map { (item) -> Int in
return item + 1
}
let filterArray = array.filter { (item) -> Bool in
return item % 2 == 0
}
let reduce = array.reduce(3) { (item1, item2) -> Int in
return item1 + item2
}
let sortArray = array.sorted { (item1, item2) -> Bool in
return item1 > item2
}
// 數組的截取
let index4 = 2
let array4 = [1,2,3,4,5]
let subArray4 = array4[0..<index4]
// 字典遍歷
let dictionary = ["one": 1, "two": 2, "three": 3]
for (key, value) in dictionary {
print(key, value)
}
c 枚舉
// Swift的枚舉可以和整型,浮點數,字符串,布爾類型關聯,不寫默認關聯字符串
enum Language: String {
case Swift
case ObjectiveC = "Objective-C"
case C
case Java
}
print(Language.Swift.rawValue)
Language.init(rawValue: "Swift")
// 可以綁定值
enum RequestResult {
case Success(Int)
case Error(String)
}
let requestResult = RequestResult.Success(1)
switch requestResult {
case .Success(let code):
print(code)
case .Error(let errorTint):
print(errorTint)
}
// 可以定義方法和計算型屬性
enum Device {
case iPad, iPhone, AppleTV, AppleWatch
func introduced() -> String {
switch self {
case .iPad: return "iPad"
case .iPhone: return "iPhone"
case .AppleWatch: return "AppleWatch"
case .AppleTV: return "AppleTV"
}
}
var year: Int {
switch self {
case .iPhone: return 2007
case .iPad: return 2010
case .AppleTV: return 2011
case .AppleWatch: return 2012
}
}
}
let introduce = Device.iPhone.introduced()
d 結構體
結構體在Swift中的地位很重要,Array Dictionary Set Int Float Double Bool String都是結構體
/*
什么時候用結構體,什么時候用類
把結構體看做值
位置(經緯度)坐標(二維坐標,三維坐標)溫度
把類看做是物體 人 車 動物
*/
/*
結構較小,適用于復制操作,相比一個class的實例被多次引用,struct更加安全
無須擔心內存泄漏或者多線程沖突問題
*/
struct Location {
var longitude: Double
var latitude: Double
// 使用Failable-Initializer
init?(coordinateString: String) {
// 非常簡潔的非空判斷,安全可靠
guard
let commaIndex = coordinateString.index(of: ","),
let firstElement = Double(coordinateString[coordinateString.startIndex..<commaIndex]),
let secondElement = Double(coordinateString[coordinateString.index(commaIndex, offsetBy: 1)..<coordinateString.endIndex])
else {
// 可能會失敗的init return nil
return nil
}
self.longitude = firstElement
self.latitude = secondElement
}
}
(2)String與NSString
// 1.String拼接用“+”,NSString是引用類型, String是值類型
let string1 = "Hello Swift"
let string2 = "Good"
let string3 = string1 + string2
// 2.獲取的長度不同
let string4 = "你好,我來了a??"
let string5: NSString = "你好,我來了a??"
print(string4.count, string5.length)
// 3.獲取字字符串
let range: NSRange = string5.range(of: "??")
let subString5 = string5.substring(with: range)
print(subString5)
let range2 = string4.range(of: "??")
let subString4 = string4[range2!]
print(subString4)
// 4.它們的長度都是1,基于unicode編碼,不同的單個字符長度不一樣,不能使用string[index]的方式訪問單個字符,使用string.startIndex string.endIndex 構成前閉后開的區間 [startIndex, endIndex)
let subString4a = string4[string4.index(before: string4.endIndex)]
print(subString4a)
let subString4b = string4[string4.startIndex..<string4.index(string4.startIndex, offsetBy: 3)]
print(subString4b)
// 5.String字符串遍歷
for charater in string4 {
print(charater)
}
// NSString 有一個方法isEqualToString 方法用來判斷兩個字符串是否完全相等,String沒有這個方法,但是因為String是值類型所以可以直接用 == 判斷是否完全相等
(3)函數
let testString = "林哲生"
//(4)函數
func sayHello(name: String = testString, greeting: String = "你們好啊", extra: Dictionary<String, String>? = nil) {
print(name + greeting)
}
/*
1.支持重載
2.函數參數可設置默認值
*/
sayHello()
sayHello(name: "1")
sayHello(greeting: "2")
sayHello(extra: ["one": "1"])
// 改變外部傳入的參數
var array = [1,2,3,4]
func sayHello(array: inout [Int]) {
array.append(5)
}
(4)可選項,安全的語言
var string1: String? = "Hello"
var string2: String? = "Hi"
// 解包判斷1
if let string1 = string1 {
print(string1)
}
func sayHello(name: String = "林哲生", greeting: String = "你們好啊", extra: Dictionary<String, String>? = nil) {
// 解包判斷2
guard let uExtra = extra else {
return
}
print(uExtra)
}
func sayHello(greeting: String = "你們好啊", extra: Dictionary<String, String>? = nil) {
// 解包判斷2
guard let uExtra = extra else {
return
}
print(uExtra)
}
// 強解包,給與默認值
(5)各種各樣的基類
NSObject(OC中所有的類都是繼承NSObject) < AnyObject(Swift中的類可以不繼承任何類) < Any(包含了函數的類型)
(6)基本數據類型都是值類型,copy - on - write
// 值類型
var arrayA = [1, 2, 3]
var arrayB = arrayA
arrayA.append(4)
arrayB.append(5)
print(arrayA)
print(arrayB)
// copy - on - write
let arrayA = [1, 2, 3]
var arrayB = arrayA
arrayA.withUnsafeBytes { print($0) }
arrayB.withUnsafeBytes { print($0) }
arrayB.append(4)
arrayB.withUnsafeBytes { print($0) }
2.Swift的動態性
(0)大綱
a 純Swift的類和繼承自NSObject的類通過runtimeAPI獲取方法屬性
b @objc之后可以被runtimeAPI獲取到,但是方法無法被替換
c dynamic后方法動態調用,可以被替換
d Swift和OC相互調用,Swift在OC類中的名字
e Swift使用關聯對象
f Swift5.0方法交換,動態訪問屬性(動態傳遞參數,動態調用方法)
(1)使用runtime API與Swift
a. @objc本意是讓OC可以調用Swift的方法,@objc所修飾的屬性,方法不能包含Swift特有的類
b. @objc 信息能使用runtime獲取,dynamic動態調用
c. 如果類繼承自Object-c的類會自動被編譯器插入@objc標識
class TestSwiftClass {
var aBool: Bool = true
var aInt: UInt = 0
var aFloat: Float = 123.45
var aDouble: Double = 1234.567
var aString: String = "abc"
@objc func printHaha() {
print("Haha")
}
@objc func printHeihei() {
print("Heihei")
}
}
class TestObject: NSObject {
var aBool: Bool = true
var aInt: UInt = 0
var aFloat: Float = 123.45
var aDouble: Double = 1234.567
var aString: String = "abc"
override var description: String {
return "TestObject"
}
func testReturnVoid() {
}
@objc dynamic func testdescription() -> String {
return "testdescription"
}
}
// 1 獲取類所有的屬性,方法
showClassRuntime(anyClass: TestSwiftClass.self)
showClassRuntime(anyClass: TestObject.self)
// 2 交換方法 ,加@objc可以獲取到
methodSwizzle(cls: TestObject.self, originSelector: #selector(getter: NSObjectProtocol.description), swizzleSelector: #selector(TestObject.testdescription))
let testObject = TestObject()
print("testObject:"+testObject.description)
// 3 加 dynamic 方法會被動態調用
methodSwizzle(cls: TestObject.self, originSelector: #selector(TestObject.testdescription), swizzleSelector: #selector(getter: NSObjectProtocol.description))
let testObject2 = TestObject()
print(testObject2.testdescription())
a .純 Swift 類沒有動態性,但在方法、屬性前添加 dynamic 修飾可以獲得動態性。
b .繼承自 NSObject 的 Swift 類,其繼承自父類的方法具有動態性,其他自定義方法、屬性需要加 dynamic 修飾才可以獲得動態性。
c .若方法的參數、屬性類型為 Swift 特有、無法映射到 Objective-C 的類型 (如 Character、Tuple),則此方法、屬性無法添加 dynamic 修飾(會編譯錯誤)
d .Swift 類在 Objective-C 中會有模塊前綴
e .仍然可以使用關聯對象技術
(2)Swift5的“Method Swizzling”
// 可繼承
@dynamicMemberLookup
class SwiftClass: NSObject {
dynamic func sayWordsA() {
print("A")
}
subscript(dynamicMember member: String) -> String {
let properties = ["nickName": "Zhou", "city": "GuangZhou"]
return properties[member] ?? "good"
}
subscript(dynamicMember member: String) -> Int {
let properties = ["nickName": 1, "city": 2]
return properties[member] ?? 3
}
}
extension SwiftClass {
@_dynamicReplacement(for: sayWordsA())
func sayWordsB() {
sayWordsA()
print("B")
}
@_dynamicReplacement(for: sayWordsA())
func sayWordsC() {
sayWordsA()
print("C")
}
}
extension SwiftClass {
var goodString: String? {
get {
return objc_getAssociatedObject(self, "goodString") as? String
}
set {
objc_setAssociatedObject(self, "goodString", newValue, objc_AssociationPolicy.OBJC_ASSOCIATION_COPY_NONATOMIC)
}
}
}