全文共8828字,预计学习时长16分钟

swiftcode怎么弄(15种快速技巧提升Swift编码能力)(1)

本文介绍的这些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

}

swiftcode怎么弄(15种快速技巧提升Swift编码能力)(2)

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中可发现,可以在完成动作(动画、网络调用等)后发送警报,或者发送包含数据的警报。

swiftcode怎么弄(15种快速技巧提升Swift编码能力)(3)

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项目数组编码到内存中的演示。

此文件的主要用例发生在应用程序的初始化运行阶段。

在此阶段,检查需要存储的预存在项目数组。如果此数组不存在,那么可以预先使用项目数组进行填充,然后将其保存到内存中供以后调用。

swiftcode怎么弄(15种快速技巧提升Swift编码能力)(4)

留言 点赞 关注

我们一起分享AI学习与发展的干货

编译组:梁晶晶、胡昕彤

相关链接:

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

如需转载,请后台留言,遵守转载规范

,