Consolidation Day II – Milestone: Projects 1-3

by | February 26, 2019

Consolidation Day II – Milestone: Projects 1-3

Jeff Summers

February 26, 2019

Now that we have gone beyond the simple foundational aspects of Swift in the 100 Days of Swift challenge, Consolidation Days have a completely different meaning. Gone are the simple quizzes or reviewing simple constructs such as variables and constants. No, these are not your grandmother’s Consolidation Days. Well, unless your grandmother is a Blac-Belt Swift Jedi Master then these are probably EXACTLY your grandmother’s Consolidation Days.

First thing to consider is your frame of mind and focus before you try to attack one of these Swift daily challenges. We have now reached a point where you can’t just mail in a day and take a quick quiz. No, we are now embarking on creating working, running applications and if you aren’t focusing on what you are doing suddenly builds are failing, simulators are crashing, and you are stuck staring at a screen of error codes that sound an awful lot like what adults sounded like in Charlie Brown programs.

For this Consolidation day we are being asked to take what we learned in the first three projects and combine that knowledge to build a new application that does a little bit of everything. The app itself is still fairly simple in what it does but it is challenging enough to make you feel a sense of accomplishment once you have finished.

For this app we are to create a table view controller and display a list of flags from around the world. Once this list is displayed the user should be able to select a flag name and be taken to a detailed view controller showing the graphic of the flag along with the country’s name. As an added feature you should provide a way for the user to share the flag image and the country name.

On the surface this shouldn’t be hard. I mean we created a table view in Project 1 where we displayed a list of image names. The user selected a file name from the list and the image was displayed on a detail view controller. Project 3 has us extend the Project 1 app to allow the user to share the image of a storm cloud. So we have already gone through a lot what is required here.

In Project 2 we took a list of flags and created a quiz that allowed the user to try and guess what the correct flag was for a particular country. From that we used the Assets.xcassets bundle to pull images to display to the user. This also taught us to create arrays of countries, sort them, and display to a view controller the images constrained by size. That too should be very helpful to us.

Given what we have been provided this project should not be too hard. Then why is it that I decided to make it way more complicated than I needed to? Instead of using the 12 flag images we were given in Project 2, why did I think it would be much cooler to pull the flags for 260 images to really test my understanding? I went through the effort to not just create the image files for 260 countries, but I also created 2 Times (@2x) and 3 Times (@3x) files and poured them into the Assets.xcassets bundle. I checked to make sure that went well as Xcode created 260 individual entries that included 3 images each for 1x, 2x, and 3x. At that point I was feeling pretty good; but just for a minute.

I created a table view controller and using the code from Project 1 where we connected to the file system I read in the list of files. I was careful to only look for images using .hasSuffix(“png”) and confidently ran the code. And there was nothing in my array. I went back through the code and poured over every line. I did a bunch of searches and read through more than a few articles. From what I could find, the Assets.xcassets bundle is not like a directory and you can’t just read files from it. The gotcha for me was that in our first project we created a folder and copied the images to that folder. In the second project the images were in the bundle, but we wrote out the array by hand and did not read it from the bundle.

The simplest thing I could have done was to just create a line of code with all 260 countries listed but in the instructions, it explicitly said that was frowned upon so that alternative went out the window. Instead I pulled the images out of the bundle and instead created a folder and placed them there. Of course what I didn’t count on was that the directory is not handled the same way as the bundle so when I loaded the array of all image files (“.png”) instead of getting an array of 260 items I got an array with 780 items since the 1x, 2x, and 3x files each met the criteria of being an image file. So, I went back to the directory and eliminated the larger images giving me the 260 array items I expected.

As I loaded the table array with the country names, I noticed all of the names included the file extension “.png”. That just did not look cool, so I went sideways yet again to try and clear that up. I kept getting error messages within Xcode stating that I was trying to modify an Optional String and give it to a different type and would die. After a few trial and error ideas, none of which worked, I finally decided to just brute force things and extend the String class to remove the last 4 characters. For those who are curious, here is the code for that:

extension String {
func stripExtension(_ extensionSeperator: Character = ".") -> String {
let selfReversed = self.reversed()
guard let extensionPosition = selfReversed.index(of: extensionSeperator) else { return self }
return String(self[..

Something to note with this code, if for some reason there was a country or file name that had a period in it then it gets kind of funky. But the odds of coming across a country name with a period were pretty slim and I didn’t want to go completely down the rabbit hole finding a solution as this was already outside the boundaries of what we were asked to do.

It worked pretty well. I called this extension when I was building the array using:

for item in items {
if item.hasSuffix(".png") {
flags.append(item.stripExtension())
}
}
flags = flags.sorted()

The last line was not part of the extension, I added that so that the country names would display sorted alphabetically in the table view controller. Once all that was done I then just modified the cellForRowAt to display the country name. I mis-read the instructions and thought we were supposed to show a small thumbnail of the flag along with the country name. I used the following to do that:

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Flag", for: indexPath)

cell.textLabel?.text = flags[indexPath.row]
cell.imageView?.image = UIImage(named: flags[indexPath.row])

return cell
}

The line including imageView took me a bit to get right. I was not sure of the attributes of cell and took a couple of attempts before getting it right. After completing the exercise, I re-read the instructions and realized that the images in the table view were extra credit so yeah me.

The detailed controller piece was pretty basic and similar to what was done in Project 1. I took the country name from the array and put the appropriate image in the imageView on the detail page. After doing that I added a share button to the navigation bar in the upper right. Using that I created a function for when the button was tapped. Here is where I got a little lazy. I assumed that the user would not want to share the name of the country without the flag image so the share actually shares text and images.

@objc func shareTapped() {
guard let image = flagImage.image?.jpegData(compressionQuality: 0.8) else {
print("No image found")
return
}

guard let text = country else {
print("No text found")
return
}

let vc = UIActivityViewController(activityItems: [text, image], applicationActivities: [])
vc.popoverPresentationController?.barButtonItem = navigationItem.rightBarButtonItem
present(vc, animated: true)
}

This was a conscious design decision. I could have created a second button for sharing separate or I suppose I could have created a dialog box asking to share one or the other or both. That just didn’t seem warranted in this case so I went with one button and no user intervention.

Of note in this code, I did guard let for both the image and the country name just in case one of the two didn’t exist but I can’t for the life of me think of a scenario where the app would not have those values. To share both pieces of data I added “[text, image]” to the activityItems parameter.

I think that is about all the weirdness I had to do. It was an interesting exercise and I learned quite a lot. It did introduce some areas that I have made notes on to follow up. Like there has to be a way to read the images out of the Assets.xcassets bundle. I can’t be the first person who wanted to do that and I am sure Apple made a way, I just don’t know it (yet). So until then, this works it just may not be as elegant as it should be.

And if anyone is looking for a list of country flag icons, I suggest FlatIcon.com. You have a couple of choices if you use their graphics. If you give full credit to the author (his is explained on their web site) then you can use them for free. If you do not want to attribute them, they have a premium download section.

Share this Article

Posted by Jeff Summers

Author, technologist, and baseball aficionado specializing in information technology and developing new and creative ways to interact with the world around us. My goal is to extend the boundaries of what is possible and find ways to make the world a better place while having fun.

0 Comments

Trackbacks/Pingbacks

  1. Consolidation Day III – Milestone: Projects 4-6 – Jeff Blogs - […] I have said before, Consolidation Days have become a lot more meaningful since we’ve moved past learning […]

Submit a Comment

Your email address will not be published. Required fields are marked *

Stay Connected

Search

More Articles

Pace Layered Architecture Categorization

Change is inevitable. Today’s computing environments are constantly in flux from internal and external forces that put demands on the systems and necessitate changes to maintain its value stream. Technology currency is a constant struggle that organizations must...

TBM, Another Holy Grail?

Technology Business Management or TBM as a term was coined around 2012 although many of the concepts making up this framework have been around for almost as long as there has been IT. In its simplest form, TBM represents the integration of business, technology, and...

Visionary or Dreamer?

Thinking back over your life you’ve met and worked with countless personality types. You have been a part of teams that struggled to complete simple tasks and the work felt meaningless. Perhaps your goal in these times was to just trudge through the mud hoping the...

Archives