Follow along at https://www.hackingwithswift.com/100/16.
This day represents the beginning of the projects in Hacking with Swift.
I have a separate repository where I've been creating projects alongside the material in the book. And you can find Project 1 here. However, this day focused specifically on a number of topics:
- Setting up Projects in Xcode
- Listing images with FileManager
- Designing our interface
Xcode's setup process is pretty straightforward, but the one thing that's probably important to note is the Organization Identifier
setting. When publishing an app to the App Store, this will need to be unique. And so, there seems to be a well-established convention of making this your website domain name in reverse, followed by the name of the app. For example: com.mysite
.
When we have a set of images that we want to load by directly specifying their paths, we can use a combination of FileManager
and Bundle
.
Bundle.main.resourcePath
will compute the dynamically generated resource path that our assets will have when our app is running on a device, and an instance of FileManager.default
can use that path, treat it as a directory, and fetch the directory's contents.
let fm = FileManager.default
let path = Bundle.main.resourcePath!
let images = try! fm.contentsOfDirectory(atPath: path)
imagePaths = images.filter({ $0.hasPrefix("nssl") })
I'm curious about image-loading strategies that involve storing images as assets catalogs — but regardless, this was a nice example of using FileManager
and Bundle
in tandem.
This section covered using UITableViewController
creating a table for our images — feeding it with the image data we generated by finding our app's image names.
It touched on overriding a few functions that seem to be staples of UITableViewController
:
tableView(_:cellForRowAt:)
tableView(_:didSelectRowAt:)
tableView(_:numberOfRowsInSection:)
Whenever we're using an array of data to drive a section, numberOfRowsInSection
can make use of its count property:
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return imagePaths.count
}
cellForRowAt
can make use of an extremely important performance optimization: dequeing reusable cells (AKA recycling views). This means that the OS can store cells as a queue in memory, and then pull from one end or the other as the user scrolls through the list. This prevents the app from potentially creating an astronomical number of unique cells.
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Picture", for: indexPath)
cell.textLabel?.text = imagePaths[indexPath.row]
return cell
}
Smashing Magazine recently had a good article that mentioned this and other handy performance techniques.