Day 22 - 100 Days of Swift

4 minute read

Project 3

Day 22 is the third project day. It is a “technique” project, which focuses on one specific iOS technology in more depth than other projects. This first one is about UIActivityViewController and sharing stuff out of your app to other places.

The first thing you do is add a UIBarButtonItem to the navigation bar in DetailViewController:

1
2
3
4
let barButton = UIBarButtonItem(barButtonSystemItem: .action,
                                target: self,
                                action: #selector(shareImage))
navigationItem.rightBarButtonItem = barButton

This leads to an error, because we don’t have a method called shareImage yet, but adding it is the next thing you do:

1
2
3
4
5
6
7
8
9
10
11
@objc func shareImage() {
    guard let image = imageView.image?.jpegData(compressionQuality: 0.8) else {
        print("No image found.")
        return
    }
    let activityVC = UIActivityViewController(activityItems: [image],
                                              applicationActivities: [])
    activityVC.popoverPresentationController?.barButtonItem =
        navigationItem.rightBarButtonItem
    present(activityVC, animated: true)
}

Basically, you unwrap the image and turn it into a .jpg, you give that to a UIActivityViewController, you set the popoverPresentationController in case it is being presented on an iPad, and then you present it. That’s it. That’s all it takes to share an image out of your app.

Screenshot of working app

The only other thing he has you do is add a line to Info.plist which tells iOS what you’re going to use access to the user’s photo library for. This string is presented when the app asks the user’s permission for access to their photo library. If you don’t have this, the app crashes when it needs to ask for permission.

Screenshot of adding Photo Library Usage string to info.plist

He also gives you three challenges. The first one is to add the name of the image to be shared along with the image. That’s pretty simple, you just need to unwrap it and then include it in the activityItems array:

1
2
3
4
5
6
7
8
9
guard let image = imageView.image?.jpegData(compressionQuality: 0.8),
        let imageName = selectedImage else {
            print("No image found.")
            return
        }
let activityVC = UIActivityViewController(activityItems: [image, imageName],
                                          applicationActivities: [])

// ... Everything else is the same

The second is to add a share button to the main view of the screen that lets you share the app itself. I’m assuming you would need an App Store link to do this well, but I just put some placeholder text instead:

1
2
3
4
5
6
7
8
9
10
11
12
13
let message = """
Check out this cool new app I'm using!
It is called 'Project1'
#app_store_link#
"""

@objc func shareApp() {
    let activityVC = UIActivityViewController(activityItems: [message],
                                              applicationActivities: [])
    activityVC.popoverPresentationController?.barButtonItem =
        navigationItem.rightBarButtonItem
    present(activityVC, animated: true)
}

It ends up looking like this:

Screenshots of sharing app challenge

The final challenge was to add a bar button to show the user their score in the flag game. First, I removed the score that I had added to the title in a previous challenge, and added a UIBarButtonItem in the setup method:

1
2
3
4
5
let barButton = UIBarButtonItem(title: "Check Score",
                                style: .plain,
                                target: self,
                                action: #selector(presentScoreAlert))
navigationItem.rightBarButtonItem = barButton

Then I just needed to add the presentScoreAlert method:

1
2
3
4
5
6
7
8
9
10
@objc private func presentScoreAlert() {
    let ac = UIAlertController(title: "Your Score",
                               message: "\(score) points after answering \(answered) questions",
                               preferredStyle: .alert)
    let action = UIAlertAction(title: "Continue",
                               style: .default,
                               handler: { _ in self.dismiss(animated: true) })
    ac.addAction(action)
    present(ac, animated: true)
}

It looks like this in the app:

Screenshots of flag app with new score alert.

You can find my versions of these projects at the end of day 22 on Github here.

Reflections

Today was good. I don’t feel like we really took a deep dive into UIActivityViewController, but it is amazing to see how much functionality you get for free with just a few lines of code. And I’m sure a lot of apps have gone a long way without providing much more configuration than we covered in today’s lesson. So that is pretty cool.