15種快速技巧,提升Swift編碼能力

2021-01-11 讀芯術

全文共8828字,預計學習時長16分鐘

本文介紹的這些Swift實用性技巧的操作說明可以用於創建iOS應用程式,希望你可從中有所收穫。

1. 可選項解包

var optional1: Int?

var optional2: Int?

// 1 - Ugly Code

func unwrap() {

if let o1 = optional1 {

if let o2 = optional2 {

// reached

}

}

}

// 2 - Clean Code

func unwrap() {

guard let o1 = optional1, let o2 = optional2 else { return }

// reached

}

解包可選變量,在一行中使用選項2處理故障。

如果兩個可選值都不是nil值,則選項2會被注釋。如果其中一個變量為nil值,則「返回」並退出此函數的範圍。

2. 三元運算符

let myBool = true

let testBool = myBool ? false : true

let testInt = myBool ? 16 : 8

//testBool equals false, testInt equals 16 because the input to the conditional is true, therefore

//the first choice is picked for each operator

//ternary

let ternary = conditional ? true : false

//vs. conditional

var ternary = false

if conditional {

ternary = true

}

通過這些有用的運算符,將條件邏輯壓縮到一行。根據狀態設置變量值。

是不是更方便?如果讀起來有點難,那麼可將這些運算符嵌套為緊湊的代碼。

//double stack

let ternaryDouble = conditional ? true : (conditional2 ? true : false)

//triple stack

let ternaryTriple = conditional ? true : (conditional2 ? true : (conditional3 ? true : false))

3. 泛型

// 1 - Ugly Code

var strings = ["Hello", "This", "Is", "A", "Test"]

var integers = [1, 2, 3, 4, 5, 6, 7]

func printStrings(_ array: [String]) {

for s in array {

print(s)

}

}

func printIntegers(_ array: [Int]) {

for i in array {

print(i)

}

}

// 1 - In Action

printStrings(strings)

printIntegers(integers)

// 2 - Clean Code

func printArray<T>(_ array: [T]) {

for item in array {

print(element)

}

}

// 2 - In Action

printArray(strings)

printArray(integers)

根據谷歌定義,泛型編程是一種編寫函數和數據類型的方法,同時對所使用的數據類型做出最小化假設。

考慮到抽象化,使用泛型可生成更為清晰的代碼,減少錯誤。

如上文所示,通過選擇選項2,可編寫一個函數(相對於多個),處理幾種不同類型的輸入。

4. 通過十六進位代碼生成UIColor

創建一個名為 UIColor+Extensions.swift的文件,包含以下代碼:

import UIKit

extension UIColor {

convenience init(hex:Int, alpha: CGFloat = 1.0) {

self.init(

red: CGFloat((hex & 0xFF0000) >> 16) / 255.0,

green: CGFloat((hex & 0x00FF00) >> 8) / 255.0,

blue: CGFloat((hex & 0x0000FF) >> 0) / 255.0,

alpha: alpha

)

}

}

恭喜,現在你可通過十六進位代碼生成不同顏色,如下所示:

let green = UIColor(hex: 0x1faf46)

let red = UIColor(hex: 0xfe5960)

let blue = UIColor(hex: 0x0079d5)

5. 使用擴展程序

import UIKit

extension UIButton {

func press(completion: @escaping() -> ()) {

UIView.animate(withDuration: 0.125, delay: 0, options: [.curveEaseIn], animations: {

self.transform = CGAffineTransform(scaleX: 0.94, y: 0.94)

}, completion: { _ in

UIView.animate(withDuration: 0.125, delay: 0, options: [.curveEaseIn], animations: {

self.transform = .identity

}, completion: { _ in

completion()

})

})

}

}

創建一個可擴展文件,包含經常重複使用的類。

在這種情況下,筆者選擇了UIButton演示添加自定義印刷功能。

現在,可在添加UIButton的地方,調用press函數模擬動畫進行放大和縮小,如下所示:

let myButton = UIButton()

myButton.press() {

//handle completion

}

6. 通過創建一個類匯集多種後端/函數調用

想像一下,你需要在應用程式內部調用一個函數來更新本地數據,如下所示:

FAB.updateData()

在該例中,FAB代表Google Firebase。現在,設想要清除Firebase,用另一個後端進行替換,這一技巧將使這種情況變得快速又簡單。

編寫代碼時,如果發現自己在應用程式中多次調用相同函數,那麼請創建一個類,將所調用函數「匯集」到一個函數中,然後調用你的網絡代碼。

例如:

// 1 - Bad Code

class MyClass1 {

init() {

FAB.updateData()

}

}

class MyClass2 {

init() {

FAB.updateData()

}

}

class MyClass3 {

init() {

FAB.updateData()

}

}

// 2 - Good Code

class Network {

func updateData() {

FAB.updateData()

}

}

class MyClass1 {

init() {

Network.updateData()

}

}

class MyClass2 {

init() {

Network.updateData()

}

}

class MyClass3 {

init() {

Network.updateData()

}

}

在選項1中,如果想要替換Firebase,需要切換出三個函數進行調用。在選項2中,只需要更新自己的網絡類。

7. guard let

除了解包選項,使用保護語句在其他方面也頗具實用性。可利用這些語句進行簡單的條件驗證檢查,以便在某些條件下將程序控制轉移到範圍之外。

例如:

// example 1 - nil checking

func checkTheText() {

guard let text = textField.text else {

return

}

//we made it this far... now we can use text for something!

updateLabel(text)

}

// example 2 - conditional checking

func conditionalCheck() {

let c1 = true

let c2 = false

let c3 = true

let c4 = true

guard c1, c2, c3, c4 else {

return

}

}

// example 3 - multiple validation checks

func validatePassword(_ password: String) -> Bool {

guard password.count >= 8 else { return false }

guard password.count <= 15 else { return false }

guard checkPasswordCharacters(password) else { return false } //must contain capital letter, special character, etc...

//password is valid

return true

}

8. 循環

// while loop

var i = 0

while 5 > i {

print(i) //output: 0 1 2 3 4

i += 1

}

// repeat

var a = 0

repeat {

print(a) //output: 0 1 2 3 4

a += 1

} while a < 5

// for loop

for c in 0...5 {

print(c) //output: 0 1 2 3 4 5

}

// for loop (no variable)

for _ in 0...3 {

print("count up") //output: count up, count up, count up, count up

}

// for loop (less than equal than)

for d in 0..<5 {

print(d) //output: 0 1 2 3 4

}

// for loop (reversed)

for z in (1..<10).reversed() {

print(z) //output: 9 8 7 6 5 4 3 2 1

}

// for loop (stride)

for g in stride(from: 1, to: 10, by: 3) {

print(g) //output: 1 4 7

}

// for loop (stride, reversed)

for k in stride(from: 3, to: 0, by: -1) {

print(k) //output: 3 2 1

}

明白易懂。多種用於創建循環的句法,並在旁邊列出相關輸出。

9. 使用枚舉確保切換語句/不同類別的項是類型安全的

// 1 - Ugly code

var marketShare: Int!

let operatingSystem = "iOS"

switch operatingSystem {

case "iOS": marketShare = 30

case "android": marketShare = 45

case "windows": marketShare = 15

case "sailfish": marketShare = 8

case "ubuntu": marketShare = 2

default: marketShare = 0

}

// 2 - Clean code

enum OS { case iOS, android, windows, sailfish, ubuntu }

var marketShare_: Int!

let operatingSystem_ = OS.iOS

switch operatingSystem_ {

case .iOS: marketShare_ = 30

case .android: marketShare_ = 45

case .windows: marketShare_ = 15

case .sailfish: marketShare_ = 8

case .ubuntu: marketShare_ = 2

}

在選項1中,可能會在switch語句中輸入一個不合適的字符串,會導致市場份額的設置值不合理。

在選項2中,我們強制此switch語句是類型安全的,因此無法輸入錯誤值並進行代碼編譯。

10. 使用回調發送完成處理程序

// 1 - Completion handlers

func myFunction(completion: @escaping() -> ()) {

UIView.animate(withDuration: 2, animations: {

//run animation

}, completion: { _ in

completion()

})

}

// 2 - Sending data through a callback: update UI upon network call

class Modal {

func getData(completion: ((_ data: String) -> Void)) {

let data = "Network data!"

completion(data)

}

}

class ViewController: UIViewController {

let model = Model()

override func viewDidLoad() {

super.viewDidLoad()

model.getData { [weak self] (data: String) in

self?.updateView(data)

}

}

private func updateView(_ data: String) {

print(data)

}

}

從選項1和選項2中可發現,可以在完成動作(動畫、網絡調用等)後發送警報,或者發送包含數據的警報。

11. 提供默認值

// "Hello World!" represents the default text we should use if the user's textInput is nil

// 1 - Ugly Code

var textInput: String?

var text = ""

if let t = textInput { text = t } else {

text = "Hello World!"

}

// 2 - Clean code

let text_ = textInput ?? "Hello World!"

在該例中,可發現兩個用於設置變量值的選項,具體取決於用戶輸入是否為nil。

12. 為便於訪問請將通用常量存儲在一個文件中

為便於使用,筆者喜歡將靜態常量存儲在一個文件中,如下所示:

import Foundation

struct Constants {

struct Colors {

static let blue = UIColor(hex: 0x111111)

static let green = UIColor(hex: 0x222222)

static let red = UIColor(hex: 0x333333)

}

struct Names {

static let myName = "Gavin"

static let myMomsName = "Marie"

static let myDadsName = "Jake"

static let mySistersName = "Jennifer"

}

}

例如,訪問UIColor:

let myColorPick = Constants.Colors.green

let sistersName = Constants.Names.mySistersName

13. 自動參考計數

強烈建議閱讀有關ARC(自動參考計數)的官方Swift文檔。

Swift使用ARC跟蹤和管理內存。這一點在使用應用程式中的幾種情況下需要牢記。

簡要介紹ARC在對象去初始化方面的影響:

試想,我們有Person這個類,Person:

class Person {

init() { print("initialized!") }

deinit { print("deinitialized!") }

}

接下來,創建三個變量。由於這三個變量是可選項,因此初始值為nil:

var ref1: Person? // nil

var ref2: Person? // nil

var ref3: Person? // nil

接下來,創建一個新的Person實例並將其分配至ref1。

ref1 = Person() // console output: "initialized!"

然後,指定ref2和ref3作為同一Person對象的參考:

ref2 = ref1 // Person

ref3 = ref1 // Person

既然所有三個參考都指向同一個Person對象,那麼我們可以將前兩個參考設置為nil,同時仍將Person對象保留在內存中,如下所示:

ref1 = nil

ref2 = nil

最後,要對Person對象去初始化,請將第三個和最後一個參考設置為nil:

ref3 = nil // console output: "deinitialized!"

14. 為函數參數提供默認參數

func printToConsole(_ messageLine1: String, _ messageLine2: String = "This is line 2!") {

print("\(messageLine1) | \(messageLine2)")

}

printToConsole("This is line 1!") // This is line 1! | This is line 2!

printToConsole("This is line one.", "This is line two.") //This is line one. | This is line two.

由上可見,為輸入參數提供默認值非常簡單。

15. 通過UserDefaults15.49/5000從內存中編碼/解碼結構

import Foundation

// - represents a single Task

struct TaskItem: Codable {

var isToggledOn: Bool

var title: String

var notes: String

}

// - handles on-device memory retrieval and storage

class MemoryManager {

static var tasks: [TaskItem]! // - static array of TaskItems that currently exists on the device

private let defaults = UserDefaults.standard // - reference to application's UserDefaults dictionary

private let DEFAULTS_KEY = "TASK_LIST" // - the key we use to retrieve/save our array of TaskItems

init() {

MemoryManager.tasks = [TaskItem]()

retrieveData()

saveData()

}

// - decode our array from memory

private func retrieveData() {

// - check if an array of TaskItems already exists in memory

var didFail = false

if let data = UserDefaults.standard.value(forKey: DEFAULTS_KEY) as? Data {

if let tasks = try? PropertyListDecoder().decode(Array<TaskItem>.self, from: data) {

MemoryManager.tasks = tasks

} else { didFail = true }

} else { didFail = true }

// - guard statement: if we had a failure then continue

guard didFail else { return }

// - we had a failure in finding a pre-existing array, create a new array of TaskItems!

MemoryManager.tasks = [

TaskItem(isToggledOn: false, title: "task 1", notes: "this is task 1"),

TaskItem(isToggledOn: false, title: "task 2", notes: "this is task 2"),

TaskItem(isToggledOn: true, title: "task 3", notes: "this is task 3"),

TaskItem(isToggledOn: false, title: "task 4", notes: "this is task 4"),

TaskItem(isToggledOn: false, title: "task 5", notes: "this is task 5"),

TaskItem(isToggledOn: true, title: "task 6", notes: "this is task 6")

]

}

// - encode our array into memory

private func saveData() {

UserDefaults.standard.set(try? PropertyListEncoder().encode(MemoryManager.tasks), forKey: DEFAULTS_KEY)

}

}

此文件演示了許多實用性功能。

在頂部,有一個標題為TaskItem的struct,符合Codable;這種一致性允許我們通過序列化格式(如JSON)對該結構進行編碼/解碼。

之後可以發現,在函數retrieveData()中,使用了guard語句和if let語句檢查UserDefault是否存在一個預先存在的TaskItem數組。

如果不存在這樣的數組,那麼會創建一個包括上述項目的新數組。

在該文件底部,可看到如何通過PropertyListEncoder、字典鍵和可選的try block塊將現有的Codable項目數組編碼到內存中的演示。

此文件的主要用例發生在應用程式的初始化運行階段。

在此階段,檢查需要存儲的預存在項目數組。如果此數組不存在,那麼可以預先使用項目數組進行填充,然後將其保存到內存中供以後調用。

留言 點讚 關注

我們一起分享AI學習與發展的乾貨

編譯組:梁晶晶、胡昕彤

相關連結:

https://medium.com/better-programming/15-quick-tips-to-improve-your-swift-code-ed390c99afcd

如需轉載,請後臺留言,遵守轉載規範

相關焦點

  • 神鬼傳奇手遊戰力提升技巧 新手快速升戰力攻略[圖]
    1、選擇高戰大公會。更新後寶石的作戰能力得到了提升,效果明顯,建議全買。寶石攢夠在合成升級,不然效果反而會差,一個5級寶石是沒有4個4級寶石給力的。3、首飾和裝備屬性洗鍊效果拔群。資源有限的情況下,優先搞齊金色首飾,加戰力很多。在材料包爛大街的時候,有心收集慢慢洗鍊屬性,提戰力也不少,而且作戰能力明顯提升。4、坐騎騎乘選擇會影響戰鬥力。
  • 15項醫保業務編碼標準發布
    15項醫保業務編碼標準應這樣貫徹執行  來源|中國醫療保險(ID:zgylbxzzs)  今日,國家醫保局官網發布《關於貫徹執行15項醫療保障信息業務編碼標準的通知》(以下簡稱《通知》),要求各地做好醫保疾病診斷和手術操作、醫療服務項目、藥品和醫用耗材等15項醫療保障信息業務編碼標準貫徹執行工作,並明確提出了4項推進信息業務編碼標準貫徹執行的工作任務。
  • 如何快速提升寫作能力?從三個維度提升寫作能力
    其實,寫作能力是要從不同的三個維度進行考慮的。包括:輸入、處理(信息加工和思考)和輸出。從以上三個維度一起提升我們的寫作能力,會進步更快,才能寫出高質量、高傳播度的文章。那麼,如何從以上三個維度提升我們的寫作能力呢?
  • 3個技巧讓社交能力迅速提升
    3個技巧讓社交能力迅速提升 2020-10-01 11:39 來源:澎湃新聞·澎湃號·湃客
  • 伊洛納技能熟練度快速提升技巧 技能熟練度怎麼提升
    今天為大家帶來的是伊洛納技能熟練度快速提升技巧,技能熟練度怎麼快速提升?這裡匯總了伊洛納技能熟練度快速提升方法,感興趣的小夥伴一起來看看吧。
  • 提升單選題命中率的15個小技巧,搞定90%題目!
    這是因為面對高考英語考試,不同的題型都有其對應的解題技巧。這些規律和技巧,能夠幫助我們在考試時,做題更加得心應手,避免手忙腳亂,成績自然穩步提升!所以今天,就不講如何背單詞,不談怎樣學語法,單講遇到真題,提高單選命中率的15個技巧!!
  • Package Swift
    Package.swift 使用在Swift 開發中替換 cocoaPod 的包管理器,簡稱 SPM,執行速度上速度更快,並且體檢最佳。
  • 學霸:《初中數學選擇題快速解題8種方法技巧》,我經常用的方法
    我們在初中學習的階段,除了去扎紮實實地打好數學的基本功和計算能力之外,我們也一定要了解考試中各種題型的解題方法和解題思路,學霸之所以是學霸不僅僅在解題思路上有個人的件數,更重要的是如何快速的解出題得出結論來,這需要通過觀察而且掌握不同的方法。
  • 通過LLVM 在 Android 上運行 Swift 代碼
    我們現在需要手動編譯和連接一個簡單的 Swift "Hello world" :// hello.swiftprint("Hello, world!");構建對象文件:$ $SDK/usr/bin/swiftc -emit-object hello.swifthello.o 裡面到底有什麼:$ nm hello_swift.o                 U __TFSSCfMSSFT21_builtinStringLiteralBp8byteSizeBw7isASCIIBi1
  • 形成全國「通用語言」 15項醫保信息業務編碼標準全部完成
    新華社北京10月8日電(記者張泉)「一病一碼」「一藥一碼」、結算信息一單集成、數據傳輸標準統一……記者8日從國家醫保局獲悉,15項醫保信息業務編碼標準已全部完成,預計到2020年將逐步落地使用,實現全國醫保系統和各業務環節的「一碼通」。
  • 研究揭示SARS-CoV-2的編碼能力
    研究揭示SARS-CoV-2的編碼能力 作者:小柯機器人 發布時間:2020/9/12 22:32:38 以色列魏茨曼科學研究院Noam Stern-Ginossar團隊揭示SARS-CoV-2的編碼能力。
  • 初中物理,提升解題速度必須掌握的三種技巧
    主要還是沒有掌握正確的方法和技巧。其實呢,初中物理沒有像大家想的那麼複雜,只要大家能根據不同題型,適時轉變思維方式,掌握巧妙的方法,看似複雜的問題,也能輕鬆快速解決。感謝百家號「人生底色看語文」的邀請,現在就結合近幾年中考物理試題,給同學們總結三種解題技巧,分享給大家,希望對同學們的學習備考有所啟發。
  • 《少年三國志零》萌新快速上手系列!戰力怎麼提升零戰力提升攻略
    少年三國志零戰力怎麼提升?在遊戲中很多玩家會遇到卡關的時候,這時候戰力的提升就是玩家的煩惱了。那麼怎麼才能快速提升戰力呢?下面就和小編一起來看看戰力提升攻略吧!少年三國志零戰力怎麼提升一、等級提升提升等級的途徑有兩種:①通過消耗體力獲得升級所需的經驗②完成每日任務獲得額外的經驗獎勵二、戰役副本通關戰役副本能夠獲得升級經驗、主將碎片和主將進階材料,累積通關星數達到一定數量後,可以領取星級寶箱。同時戰役副本還可以進行掃蕩,能夠幫助少年們快速消耗溢出的體力,短時間內快速升級。
  • CPAT:轉錄本蛋白編碼能力預測軟體
    對於轉錄組測序的數據而言,組裝得到轉錄本之後,首先要做的就是區分蛋白編碼和非蛋白編碼的RNA。目前針對這一問題,有多種解決方案,基本可以分為以下兩類alignment-basedalignment-free第一種算法基於序列比對,可以較好的識別保守性較好的蛋白編碼基因, 包括CPC,PhyloCSF等軟體; 第二種算法不需要比對
  • 喀什地區積極做好人口普查編碼工作
    人口普查編碼工作是整個普查的關鍵環節,編碼工作質量將直接影響人口普查的數據質量。為做好第七次全國人口普查長表行業、職業編碼工作,切實提高編碼工作質量,比對複查工作結束後,喀什地區各縣(市)全面吹響行職業編碼工作的號角,在參加完自治區編碼培訓後,按照《普查行職業編碼工作細則》要求,各縣(市)人普辦迅速組織編碼員,於12月11日開展行職業編碼復訓工作。培訓分為理論講解和業務實操。
  • 怎麼讓兔子快速繁殖,有不少的技巧需掌握,對提升收入很有幫助
    導讀:大家好,我是百家號作者:傳誦著自由勇敢的鳥,每日和大家分享精彩的原創內容,希望大家能夠喜歡,今天我們分享的話題是:怎麼讓兔子快速繁殖,有不少的技巧需掌握,對提升收入很有幫助現在養兔子算是農村比較熱門的一種項目了
  • 8個Excel超實用技巧,讓你的辦公效率快速提升
    08:11 來源: Excel與財務 舉報   今天阿鍾老師再分享一些Excel超實用小技巧
  • 谷歌為何要養蘋果的親兒子Swift?原來意在可微分編程
    現在,假設說有 n 篇能將準確度提升 2% 的論文都遇到了這種情況,那麼產業界將錯失準確度顯著提升 (1.02^n)% 的機會,而原因不過是沒有合適的工具罷了。如果 n 很大,那就太讓人遺憾了。速度在某些情況中,同時使用 Python 與快速軟體庫依然還是會很慢。
  • GTX 1650砍掉圖靈架構編碼器:性能損失15%
    除了繼續精簡流處理器和顯存,並且不支持光線追蹤、DLSS深度學習抗鋸齒(至少目前沒有說會開放),GTX 1650其實還偷偷地在多媒體編碼上縮了水。根據NVIDIA的說法,NVENC編碼器在圖靈架構上的性能提升了大約15%。這意味著,GTX 1650儘管功耗發熱都很低,體積也可以做的很小巧,但很顯然,它並不適合做HTPC、視頻編碼轉碼、遊戲直播等工作,效率會比GTX 1660或者更高端的圖靈卡要明顯第一個檔次。
  • 提供新冠病毒編碼的全部29種蛋白質表達質粒,浦東這一設施...
    為了增強我國快速應對公共衛生事件能力,上海蛋白質設施已建立了我國自己的蛋白質庫,所有新冠病毒編碼的29種蛋白質表達質粒的構建已經全部完成,向全球開放並提供服務,以實現蛋白質資源的快速共享,助力新冠肺炎病毒的防治研究。蛋白質庫一期以蛋白質表達質粒庫為主,提供蛋白質表達質粒的存儲和寄送服務。