Swift005-轉(zhuǎn)型 可選鏈 其他知識點

Swift005-轉(zhuǎn)型 可選鏈 其他知識點

轉(zhuǎn)型

is 用于檢測值的類型,as 用于轉(zhuǎn)換類型。

import UIKit

class MyBaseClass {
    var baseName: String
    init(name: String) {
        self.baseName = name
    }
}

class MyAppleClass: MyBaseClass {
    var myPrice: Float
    init(name: String, price: Float) {
        self.myPrice = price
        super.init(name: name)
    }
}

class MyPenClass: MyBaseClass {
    var myColor: UIColor
    init(name: String, color: UIColor) {
        self.myColor = color
        super.init(name: name)
    }
}

class CastingTest: NSObject {

    lazy var myClassArray = [MyAppleClass(name: "富士", price: 2.5),
                             MyPenClass(name: "好得利", color: UIColor.blue),
                             MyAppleClass(name: "金帥", price: 3.3)]

    public class func testBasic() {
        CastingTest().testIs()
        CastingTest().testAs()
    }

    private func testIs() {

        for item in myClassArray {
            if item is MyAppleClass {
                let apple = item as! MyAppleClass
                print("\(apple.baseName) \(apple.myPrice)")
            } else if item is MyPenClass {
                let pen = item as! MyPenClass
                print("\(pen.baseName) \(pen.myColor)")
            }
        }
    }

    private func testAs() {
        // 向下轉(zhuǎn)型,用類型轉(zhuǎn)換操作符(as? 或 as!)
        // 當不確定向下轉(zhuǎn)型是否成功時,用類型轉(zhuǎn)換的條件形式(as?)。
        // 只確定向下轉(zhuǎn)型一定會成功時,才使用強制形式(as!)。當試圖向下轉(zhuǎn)型為一個不正確的類型時,強制形式會觸發(fā)一個運行時錯誤。
        for item in myClassArray {
            if let apple = item as? MyAppleClass {
                print("\(apple.baseName) \(apple.myPrice)")
            } else if let pen = item as? MyPenClass {
                print("\(pen.baseName) \(pen.myColor)")
            }
        }
    }

}

可選鏈

通過在屬性、方法、或下標腳本的可選值后面放一個問號(?),即可定義一個可選鏈。

  • 如果目標有值,調(diào)用就會成功,返回該值
  • 如果目標為nil,調(diào)用將返回nil

感嘆號(!)強制展開方法,屬性,下標腳本可選鏈

  • 如果目標有值,調(diào)用就會成功,返回該值
  • 如果目標為nil,強制展開則報錯

fatal error: unexpectedly found nil while unwrapping an Optional value

其他知識點

父類又叫超類
如果要重寫父類中的方法,需要加 override
如果要訪問父類中的方法(子類對象訪問父類方法)用super(此時super表示self當前對象)

重寫屬性
你可以提供定制的 getter(或 setter)來重寫任意繼承來的屬性,無論繼承來的屬性是存儲型的還是計算型的屬性。

子類并不知道繼承來的屬性是存儲型的還是計算型的,它只知道繼承來的屬性會有一個名字和類型。所以你在重寫一個屬性時,必需將它的名字和類型都寫出來。

注意點:
如果你在重寫屬性中提供了 setter,那么你也一定要提供 getter。
如果你不想在重寫版本中的 getter 里修改繼承來的屬性值,你可以直接通過 super.someProperty來返回繼承來的值,其中someProperty是你要重寫的屬性的名字。

重寫屬性觀察器
你可以在屬性重寫中為一個繼承來的屬性添加屬性觀察器。這樣一來,當繼承來的屬性值發(fā)生改變時,你就會監(jiān)測到。
注意:你不可以為繼承來的常量存儲型屬性或繼承來的只讀計算型屬性添加屬性觀察器

防止重寫
我們可以使用 final 關(guān)鍵字防止它們被重寫。
如果你重寫了final方法,屬性或下標腳本,在編譯時會報錯。
你可以通過在關(guān)鍵字class前添加final特性(final class)來將整個類標記為 final 的,這樣的類是不可被繼承的,否則會報編譯錯誤。

__weak 與__unretained有何區(qū)別?
__weak修飾的弱引用,如果指向的對象被銷毀,那么指針會立馬指向nil
__unretained修飾的弱引用,如果指向的對象被銷毀,它的指針依然會指向之前的內(nèi)存地址,很容易產(chǎn)生野指針(僵尸對象)

swift中Error

public protocol Error {
}

extension Error {
}

extension Error where Self.RawValue : SignedInteger {
}

extension Error where Self.RawValue : UnsignedInteger {
}

蘋果文檔第一個例子

// 枚舉對Int值處理可能的Error分類
enum IntParsingError: Error {
    case overflow
    case invalidInput(Character)
}

// 擴展Int
extension Int {
    init(validating input: String) throws {
        // ...
        let c = _nextCharacter(from: input)
        if !_isValid(c) {
            throw IntParsingError.invalidInput(c)
        }
        // ...
    }
}

// 具體使用(捕獲)
do {
    let price = try Int(validating: "$100")
} catch IntParsingError.invalidInput(let invalid) {
    print("Invalid character: '\(invalid)'")
} catch IntParsingError.overflow {
    print("Overflow error")
} catch {
    print("Other error")
}
// Prints "Invalid character: '$'"

第二個例子

// 自定義錯誤輸出結(jié)構(gòu)體
struct XMLParsingError: Error {
    enum ErrorKind {
        case invalidCharacter
        case mismatchedTag
        case internalError
    }

    let line: Int
    let column: Int
    let kind: ErrorKind
}
// 拋出錯誤
func parse(_ source: String) throws -> XMLDoc {
    // ...
    throw XMLParsingError(line: 19, column: 5, kind: .mismatchedTag)
    // ...
}
// 具體應(yīng)用
do {
    let xmlDoc = try parse(myXMLData)
} catch let e as XMLParsingError {
    print("Parsing error: \(e.kind) [\(e.line):\(e.column)]")
} catch {
    print("Other error: \(error)")
}
// Prints "Parsing error: mismatchedTag [19:5]"

Alamofire中的錯誤示例

Alamofire中的錯誤處理,用單獨的一個文件AFError來管理使用中的錯誤,其中自定義了枚舉

public enum AFError: Error {
                                encoding process.
    public enum ParameterEncodingFailureReason {
        case missingURL
        case jsonEncodingFailed(error: Error)
        case propertyListEncodingFailed(error: Error)
    }

    
    public enum MultipartEncodingFailureReason {
        case bodyPartURLInvalid(url: URL)
        case bodyPartFilenameInvalid(in: URL)
        case bodyPartFileNotReachable(at: URL)
        case bodyPartFileNotReachableWithError(atURL: URL, error: Error)
        case bodyPartFileIsDirectory(at: URL)
        case bodyPartFileSizeNotAvailable(at: URL)
        case bodyPartFileSizeQueryFailedWithError(forURL: URL, error: Error)
        case bodyPartInputStreamCreationFailed(for: URL)

        case outputStreamCreationFailed(for: URL)
        case outputStreamFileAlreadyExists(at: URL)
        case outputStreamURLInvalid(url: URL)
        case outputStreamWriteFailed(error: Error)

        case inputStreamReadFailed(error: Error)
    }

    
    public enum ResponseValidationFailureReason {
        case dataFileNil
        case dataFileReadFailed(at: URL)
        case missingContentType(acceptableContentTypes: [String])
        case unacceptableContentType(acceptableContentTypes: [String], responseContentType: String)
        case unacceptableStatusCode(code: Int)
    }

    
    public enum ResponseSerializationFailureReason {
        case inputDataNil
        case inputDataNilOrZeroLength
        case inputFileNil
        case inputFileReadFailed(at: URL)
        case stringSerializationFailed(encoding: String.Encoding)
        case jsonSerializationFailed(error: Error)
        case propertyListSerializationFailed(error: Error)
    }

    case invalidURL(url: URLConvertible)
    case parameterEncodingFailed(reason: ParameterEncodingFailureReason)
    case multipartEncodingFailed(reason: MultipartEncodingFailureReason)
    case responseValidationFailed(reason: ResponseValidationFailureReason)
    case responseSerializationFailed(reason: ResponseSerializationFailureReason)
}

作者還將AFError進行了擴展,增加部分判斷的方法,比如判斷是否是無效的URL:

// MARK: - Error Booleans

extension AFError {
    /// Returns whether the AFError is an invalid URL error.
    public var isInvalidURLError: Bool {
        if case .invalidURL = self { return true }
        return false
    }
}

同時拓展中也遵守了LocalizedError協(xié)議來重寫errorDescription屬性,并且對已經(jīng)分類enum的自定義錯誤類型進行拓展重寫了屬性localizedDescription,這樣就構(gòu)成了項目中完整的錯誤處理機制。比如在Alamofire編碼解析方法方法encode中,有這么一段代碼

do {
    let data = try JSONSerialization.data(withJSONObject: jsonObject, options: options)
    if urlRequest.value(forHTTPHeaderField: "Content-Type") == nil {
        urlRequest.setValue("application/json", forHTTPHeaderField: "Content-Type")
    }
    urlRequest.httpBody = data
} catch {
    throw AFError.parameterEncodingFailed(reason: .jsonEncodingFailed(error: error))
}

其中就是對于JSON序列化時,通過 do { try } catch 的方式來捕獲錯誤,如果捕獲到,將拋出已經(jīng)自定義好的 AFError.parameterEncodingFailed(reason: .jsonEncodingFailed(error: error)) 類型錯誤。

致命錯誤

喵神舉例的兩個使用的場景:

1.父類中的某些方法,不想讓別人調(diào)用,可以在方法中加上fatalError,這樣子類如果想到用必須重寫
2.對于其他一切我們不希望別人隨意調(diào)用,但是又不得不去實現(xiàn)的方法,我們都應(yīng)該使用 fatalError 來避免任何可能的誤會。

required init?(coder aDecoder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
}

原文請移步

圖片放入工程兩個方式

1.Assets.xcassets內(nèi),同時生成描述文件Contents.json。且在打包后以Assets.car的形式存在,不能直接打開(據(jù)說工具ThemeEngine可以打開)。
以此方式放入的圖片并不在mainBundle中,不能使用contentOfFile這樣的API來加載圖片,interface builder中使用圖片時不需要后綴和倍數(shù)標識(@2x這樣的)
2.在工程建立專門放圖片的文件夾,然后放入圖片

Assets優(yōu)勢:

1.性能好,節(jié)省Disk。Asset Catalogs會用一個高度優(yōu)化的特殊格式來存所有圖片,而不是一個一個的單獨的圖片資源,會更少的涉及頻繁Disk I/O操作,且會按需下載適合你機型的合適分辨率的圖片資源;
2.相對安全。圖片資源得到一定程度保護(Asset.car不易打開)

swift中Data獲取bytes數(shù)組

方法1:使用 [UInt8] 新的構(gòu)造函數(shù)

/// 使用(data as NSData).bytes 并不優(yōu)雅  畢竟要盡量脫離OC的框架
/// data是結(jié)構(gòu)體  使用[UInt8]構(gòu)造方法得到data的byte數(shù)組
let bytes = [UInt8](data)

方法2:通過 Pointer 指針獲取

let bytes = data.withUnsafeBytes {
    [UInt8](UnsafeBufferPointer(start: $0, count: data.count))
}
print(bytes)
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容