Challenge Solution: How to read any post on Reddit

In my last tutorial, I posed a challenge to you all,

Make it so you can view the posts text, useful for subreddit like r/tifu.

In the last tutorial we made it so you could view the hot posts of any subreddit



Today, we’re going to make it so you can actually view the text from those posts.

Continuing from where we left off

Open the .xcodeproj we created last time, it should be called RedditTutorial.xcodeproj, but it may be something different based on what you named it.

The first thing we’ll do is create a new InterfaceController, to contain the post text (selftext).

Go to your Interface.storyboard and open the objects library by pressing ⇧⌘L or by clicking the button shown below

Search for ‘Interface Controller’, and drag it onto your storyboard.

Now set the identifier of the InterfaceController to viewPost. Identifiers allow you to push (or present) that controller from anywhere in your code.

Now add a ‘Label’ (WKInterfaceLabel) to that InterfaceController. Just like in the last tutorial, set the ‘Lines’ to 0.

Now we need to create a new class for this new InterfaceController.

Go to File > New > File or press ⌘N. Create a new watchOS > WatchKit Class. Call it RedditPostViewerController, and ensure it’s a subclass of WKInterfaceController

Go back to your Interface.storyboard and set the class of your new InterfaceController to your new RedditPostViewerController class. Make sure you have “Inherit Module From Target” checked too!

Now we can connect our label to an @IBOutlet in our RedditPostViewerController class.

Connect your label and call it postText

Now that view is setup, we need to configure the data sources for it. Jump back to RedditPosts.swift, where we setup the title object last time.

Add a variable to your RedditPost struct, underneath title, add

var postText: String

And in the initialiser, add a new guard statement (or another condition to your existing guard statement)

guard let postText = data["selftext"] as? String else {return nil}

Now you just need to configure your newly create self.postText variable to be equal to the new postText string you just created.

self.postText = postText

Your RedditPost struct should now look like this

struct RedditPost: Codable{
    var title: String
    var postText: String
    
    init?(json: [String: Any]) {
        guard let data = json["data"] as? [String: Any],
            let title = data["title"] as? String,
            let postText = data["selftext"] as? String else {return nil}
        self.title = title
        self.postText = postText
    }
}

We’re nearly done!

Go back to your InterfaceController.swift and add a new function.

In our last your we didn’t create a class-scope variable for our posts, before we proceed, we need to do that.

Underneath you’re redditTable @IBOutlet, add

 var posts = [RedditPost?]()

Now in your URLSession closure, where we call self.setupTable, just before that add

self.posts = posts.posts

Now that we have self.posts, we can implement a new function from WKInterfaceTable

override func table(_ table: WKInterfaceTable, didSelectRowAt rowIndex: Int) {
        
}

As the name implies, this function is called when one of the posts is tapped.

Lets get the post from the cell which was tapped

 guard let post = self.posts[rowIndex] else {return}

Now let’s push to the RedditPostViewerController, which we gave the identifier of viewPost to.

self.pushController(withName: "viewPost", context: Any?)

Now that context argument there specifies the data we’re going to be passing to this controller we’re presenting, since we want to view a post, we pass that as the context

self.pushController(withName: "viewPost", context: post)

So close now!

Lastly, go to your RedditPostViewerController.swift file, and in your awake(withContext context: Any?) function, attempt to unwrap that context as a RedditPost

guard let post = context as? RedditPost else {
           self.pop()
       return
}

What the above code does is try to take the context object and cast it to a RedditPost type, if it fails, it pops off the view controller stack, which means it will dismiss itself.

Now we can set our postText text to be equal to our post.postText

 self.postText.setText(post.postText)

Go ahead and run your app and navigate to a text-based subreddit like r/tifu.

Click on a post, and you should be able to read it

Ta-dah!

You have now created an app which can navigate to any subreddit and read the text from that post!

Challenge

NOTE: I won’t be posting a solution for this challenge, but I would love to see if you complete it! Tweet it to me @WillRBishop

Your challenge is to add images to the post browsing view.

Hint: Just like we got title and selfpost, that JSON data we get from Reddit contains a lot more information (including some image related stuff)

The End

Thus concludes tutorial 1, I hope you enjoyed reading it!