SwiftUI 学习笔记 29:项目 5-1 单词游戏
这个项目将是另一个游戏,尽管实际上这只是我介绍更多Swift和SwiftUI知识的一种偷偷摸摸的方式!游戏将向玩家显示一个随机的八个字母的单词,并要求他们用单词来制作单词。例如,如果入门单词为“ alarming”,则它们可能拼写为“ alarm”,“ ring”,“ main”等。
沿途你会见到的方式List,onAppear(),Bundle,fatalError(),等等-所有有用的技能,你会使用几年来。你还可以得到一些练习用@State,Alert,NavigationView,多,你应该一边可以欣赏-这是我们最后一次容易的项目!
List 的使用
我们有的时候使用List作为列表时,列表的内容会分为静态数据和动态数据。
静态
1 | List { |
动态
1 | List { |
自己动
1 | List(0..<5) { |
动静结合
1 | List { |
分组动静结合
1 | List { |
更改List样式
1 | .listStyle(GroupedListStyle()) |
遍历数组
1 | struct ContentView: View { |
同理,ForEach
也可以这样写:
1 | List { |
捆绑包
当我们使用Image视图时,SwiftUI会知道在应用程序的资产目录中查找插图,它甚至会自动调整插图,以便为当前的屏幕分辨率加载正确的图片–这就是我们之前查看的@ 2x和@ 3x内容。
对于其他数据,例如文本文件,我们需要做更多的工作。如果你具有特定的数据格式(例如XML或JSON),这也适用-无论加载哪种文件类型,它都需要完成相同的工作。
Xcode构建你的iOS应用时,会创建一个称为“捆绑包”的东西。这种情况在包括macOS在内的所有Apple平台上都会发生,它允许系统将一个应用程序的所有文件存储在一个位置-二进制代码(我们编写的实际已编译Swift东西),所有插图,我们提供的任何其他文件需要,我们的Info.plist文件,以及更多,全部集中在一个地方。
将来,随着技能的提高,你将学习如何在单个应用程序中实际包含多个捆绑软件,并允许你在单个iOS应用程序捆绑软件中编写Siri扩展,iMessage应用程序,watchOS应用程序等内容。 ,称为主捆。
所有这些都很重要,因为通常要在捆绑包中查找放置在其中的文件。这使用了一种称为的新数据类型URL,该数据类型几乎存储了你的实际想法:一个URL,例如https://www.hackingwithswift.com。但是,URL不仅比存储网址更强大-它们还可以存储文件的位置,这就是为什么它们在这里有用的原因。
让我们开始编写一些代码。如果要读取主应用程序捆绑包中文件的URL,请使用Bundle.main.url()。如果该文件存在,则会将其发送回给我们,否则我们会回来的nil,所以这是可选的URL。这意味着我们需要像这样拆开包装:
1 | if let fileURL = Bundle.main.url(forResource: "some-file", withExtension: "txt") { |
里面的内容URL并不重要,因为iOS使用了无法猜测的路径-我们的应用程序位于自己的沙箱中,我们不应该尝试在其外部读取内容。
有了网址后,我们可以使用特殊的初始化程序将其加载到字符串中String(contentsOf:)。我们给它一个文件URL,如果可以加载,它将发送一个包含该文件内容的字符串。如果无法加载,则会引发错误,因此你需要使用try或try?类似方式调用它:
1 | if let fileContents = try? String(contentsOf: fileURL) { |
通过某个符号分割字符串为数组
使用.components(separateBy:<>)
1 | let input = "a b c" |
1 | let input = """ |
数组返回一个随机项
还记得SwiftUI 学习笔记 21:项目 2-2 制作猜国旗应用吗?在这里选择随机数组用的是先生成一个随机数var correctAnswer = Int.random(in: 0...2)
,然后处理这个随机数这种方法。但是我们如果只是单纯需要返回一个随机项呢?
Swift提供了另一个有用的选择:该randomElement()方法从数组中返回一个随机项。
例如,这将从我们的数组中读取一个随机字母:
1 | let letter = letters.randomElement() |
删除字符串开头和结尾某种字符
另一个有用的字符串方法是trimmingCharacters(in:),它要求Swift从字符串的开头和结尾删除某些种类的字符。这使用了一种称为的新类型CharacterSet,但是大多数时候我们想要一种特殊的行为:删除空格和换行符–指的是同时包含空格,制表符和换行符。
这种行为非常普遍,它内置在CharacterSet结构中,因此我们可以要求Swift在字符串的开头和结尾处修剪所有空格,如下所示:
1 | let trimmed = letter?.trimmingCharacters(in: .whitespacesAndNewlines) |
检查错误单词
我想介绍一下字符串功能的最后一部分,那就是检查拼写错误的单词的能力。
该功能通过类提供UITextChecker。你可能没有意识到这一点,但是该名称的“ UI”部分带有两个附加含义:
此类来自UIKit。但是,这并不意味着我们正在加载所有旧的用户界面框架。我们实际上是通过SwiftUI自动获取的。
它是使用Apple的较旧语言Objective-C编写的。我们不需要编写Objective-C来使用它,但是对于Swift用户来说,API有点笨拙。
检查字符串中拼写错误的单词总共需要四个步骤。首先,我们创建一个要检查的单词以及一个UITextChecker可以用来检查该字符串的实例:
1 | let word = "swift" |
其次,我们需要告诉检查器我们要检查多少字符串。如果你想象一个文字处理应用程序中的拼写检查器,则可能只想检查用户选择的文本,而不是整个文档。
但是,有一个陷阱:Swift使用非常聪明,非常先进的字符串处理方式,从而使其可以使用复杂字符(例如表情符号)的方式与使用英语字母的方式完全相同。然而,Objective-C中并没有使用存储字母的这种方法,这意味着我们需要问斯威夫特利用我们的所有字符的整个长度,这样创造一个Objective-C字符串范围:
1 | let range = NSRange(location: 0, length: word.utf16.count) |
UTF-16是所谓的字符编码 -一种将字母存储在字符串中的方法。我们在这里使用它,以便Objective-C可以了解Swift的字符串是如何存储的;对于我们来说,这是一种很好的桥接格式。
第三,我们可以要求文本检查器报告在单词中发现任何拼写错误的地方,传递要检查的范围,在该范围内开始的位置(因此我们可以执行“查找下一个”之类的操作),是否应该换行一旦到达末尾,以及字典使用哪种语言:
1 | let misspelledRange = checker.rangeOfMisspelledWord(in: word, range: range, startingAt: 0, wrap: false, language: "en") |
这会返回另一个Objective-C字符串范围,告诉我们在哪里发现了拼写错误。即使那样,这里仍然存在一个复杂性:Objective-C没有任何可选概念,因此依赖于特殊值来表示丢失的数据。
在这种情况下,如果Objective-C范围返回为空(即,因为字符串正确拼写而没有拼写错误),那么我们将返回特殊值NSNotFound。
因此,我们可以检查拼写结果,看是否有这样的错误:
1 | let allGood = misspelledRange.location == NSNotFound |
参考资料
- 感谢你赐予我前进的力量