Modifying the values of UserDefaults when debugging
Quickly Testing.
Open the scheme panel of your project and set up arguments in Arguments Passed On Launch with format -argument_name argument_value, and then you can read these key-values through UserDefaults.
The setting operation will truly modify the value of the key in UserDefaults, but you can only read the original value you set in the arguments list. Once you remove these arguments from the list, all behaviors of UserDefaults will get right.
1 2
UserDefaults.standard.set(0, forKey: "first_launch") // No effect. print(UserDefaults.standard.bool(forKey: "first_launch")) // true. always be the value set in arguments list.
传入 KeyPath 作为函数
Swift 5.2新特性,使用 map 等函数来进行数据转换时是更加简洁了,一个小小的改动。
1 2 3 4 5 6 7 8 9 10 11 12 13
structMovie { var name: String var isFavorite: Bool ... }
let movies: [Movie] = loadMovies()
// Equivalent to movies.map { $0.name } let movieNames = movies.map(\.name)
// Equivalent to movies.filter { $0.isFavorite } let favoriteMovies = movies.filter(\.isFavorite)
funchandle(_character: Character) { switch character { case"<": parseElement() case"#": parseHashtag() case \.isNumber: parseNumber() case \.isNewline: startNewLine() default: parseAnyCharacter() } }
计算属性和有返回值方法中如果自有一个表达式可以省略 return
好用
1 2 3 4 5 6 7 8 9
extensionMarkdownReader { var isAtStart: Bool { index == string.startIndex } var didReachEnd: Bool { index == string.endIndex } var currentCharacter: Character { string[index] } funcencodeCurrentCharacter() -> String { currentCharacter.encoded() } }
Swift5.1 中枚举的关联值也可以使用默认参数
撒花
1 2 3 4 5 6 7 8 9 10 11
// Associated enum value defaults are specified the same way as // default function arguments: enumContent { case text(String) case image(Image, description: String? =nil) case video(Video, autoplay: Bool=false) }
// At the call site, any associated value that has a default // can be omitted, and the default will be used: let video =Content.video(Video(url: url))
// Here we have three highly related expressions that are // all throwing, requiring separate assignments and separate // 'try' keywords: let contentFolder =tryFolder.current.subfolder(named: "content") let templatesFolder =tryFolder.current.subfolder(named: "templates") let output =tryFolder.current.createSubfolderIfNeeded(withName: "output")
// By combining them all into a tuple, we only need one // 'try', and can easily group our data into a single, // lightweight container: let folders =try ( content: Folder.current.subfolder(named: "content"), templates: Folder.current.subfolder(named: "templates"), output: Folder.current.createSubfolderIfNeeded(withName: "output") )
// The call sites also become really nice and clean, with // increased "namespacing" for our local variables: readFiles(in: folders.content) loadTemplates(from: folders.templates)
用函数来联合变量
最后我们将生成一个无参闭包,针对一些闭包 API 可以直接传递,并且不需要在闭包当中捕获 self。
privatefuncprocessNext() { // When unwrapping an optional tuple, you can assign the members // directly to local variables. guardlet (image, transform) = queue.first else { return }
let context =Context() context.draw(image) context.apply(transform) ... } }
// This produces a '() -> Void' closure which is a reference to the // given view's 'removeFromSuperview' method. let closure =UIView.removeFromSuperview(view)
// We can now call it just like we would any other closure, and it // will run 'view.removeFromSuperview()' closure()
// This is how running tests using the Swift Package Manager on Linux // works, you return your test functions as closures: extensionUserManagerTests { staticvar allTests = [ ("testLoggingIn", testLoggingIn), ("testLoggingOut", testLoggingOut), ("testUserPermissions", testUserPermissions) ] }
在 for-loop 循环中使用 where
如果你需要在循环中使用 if 来筛选数据,那不妨使用 where 来让代码的结构更加清晰
1 2 3 4 5 6 7 8 9 10 11
funcarchiveMarkedPosts() { for post in posts where post.isMarked { archive(post) } }
funchealAllies() { for player in players where player.isAllied(to: currentPlayer) { player.heal() } }
很常用,例如一个特殊 API 返回的数据类型不通用,但是又想使用 Model 的便利性,此时创建一个全局的 Model 就太过浪费了,在当前类型的作用域下创建一个 Model 是一个不错的方法。当然也包括了 UI 模块,一个 UI 模块内部的更小模块,无须占用全局的类型名称,可以创建在当前模块的作用域下。
publicstructMap { publicstructModel { publiclet size: Size publiclet theme: Theme publicvar terrain: [Position : Terrain.Model] publicvar units: [Position : Unit.Model] publicvar buildings: [Position : Building.Model] } publicenumDirection { case up case right case down case left } publicstructPosition { publicvar x: Int publicvar y: Int } publicenumSize: String { case small ="S" case medium ="M" case large ="L" case extraLarge ="XL" } }