TJ Barber

I have overly caffeinated thoughts on iOS development and other random things.

Codable is here!

Well, for the most part. As of today's writing, iOS 11 is going to be released to the public tomorrow which (should) mean Xcode 9 will be released to the App Store as well. That means a ton of Swift 4 goodness, and the one I'm most excited about it the new protocol Codable.

Apple describes Codable as "a type that can convert itself into and out of an external representation." Basically what this means for us is that we can take JSON and convert it into one of our objects or structs that conform to Codable and then take it and convert it back to JSON with no problem. JSON parsing in Swift has been a pain for awhile now, and our best way of handling it was something like this:


extension HubbleImageData {
    convenience init?(json: [String: Any]) {
        
        struct Key {
            static let id = "artistName"
            static let name = "name"
            static let newsName = "news_name"
            static let collection = "collection"
            static let mission = "mission"
        }
        
        guard let id = json[Key.id] as? Int,
            let name = json[Key.name] as? String,
            let newsName = json[Key.newsName] as? String,
            let collection = json[Key.collection] as? String,
            let mission = json[Key.mission] as? String else {
                return nil
        }
        
        
        self.init(id: id, name: name, newsName: newsName, collection: collection, mission: mission)
    }
}

Major pain. This is just an extension on top of our HubbleImageData struct and doesn't include the actual init method or our struct's properties.

So what would this look like if we used Codable on Swift 4? Let's take a look.

struct HubbleImageData: Codable {
    let id: Int
    let name: String
    let newsName: String
    let collection: String
    let mission: String
    
    enum CodingKeys: String, CodingKey {
        case id
        case name
        case newsName = "news_name"
        case collection
        case mission
    }
}

That's the entirety of our HubbleImageData struct. No need for a convenience initializer or even a custom init method. Our struct is good to go. So how will we use this?

This is an example of how we would handle our JSON and Codable conformant structs in the callback function of a standard URLSession data task:

if let data = data {
	let decoder = JSONDecoder()
    do {
        let hubbleImageData = try! decoder.decode([HubbleImageData].self, from: data)
        DispatchQueue.main.async {
            completion(hubbleImageData, nil)
        }
    } catch (let e) {
        // FIXME: - In real life do actual error handling!
        fatalError(e.localizedDescription)
    }
}

You'll notice that in the decode method I pass the decoder an array of HubbleImageData, and the reasoning behind that is the Hubble Imagery API sends us an array of JSON objects. By passing the array of HubbleImageData as the method's parameter, the decoder will return that back to us with actual data.

This is why I'm so excited about Codable! JSON parsing in Swift has been something I haven't looked forward to in the past. I'm not a fan of pulling packages into my code if I don't absolutely need to, so for me using SwiftyJSON (or even Alamofire for that matter) just isn't something I want to do most of the time. I don't judge anyone who does, it's just not for me. Codable is going to make the lives of all of us much easier, so go give it a shot!

Here's to cleaner codebases. :)

P.S. If you want more information on how to use Codable, I highly recommend this article by Ben Scheirman. This is how I learned how to use Codable in the first place and is a great resource on everything from just starting out to handling edge cases. Good luck, and happy coding!

An Introduction to Generics in Swift

Generics have been something that have confused me a lot in the past when coming from a JavaScript-heavy web development background, so when I came to Swift and started using it as my main language of choice I realized I had a lot to learn (which is never a bad thing).

For those who don't know, languages such a JavaScript, Ruby, and Python are dynamically typed languages. This means that the type of a variable is deduced by the system at runtime and (supposedly) makes the life of a developer easier because you don't have to specify a variable's type in code. Languages such as Swift, C, and Kotlin are statically typed languages which means the opposite. You have to specify the type of a variable and that variable's type is not allowed to change in its lifetime or the compiler will complain.

But what about when you have an object such as an array, where neither you or the compiler know what type is going to go into it? That's where generics come in.

Big Nerd Ranch's book Swift Programming describes generics in the following way:

Swift generics allow you to write types and functions that use types that are not yet known to you or the compiler. Many of the built-in types including optionals, arrays, and dictionaries, are implemented using generics.

So what does the concept of a generic look like? Let's look at this example from Apple's documentation:

struct IntStack {
    var items = [Int]()
    mutating func push(_ item: Int) {
        items.append(item)
    }
    mutating func pop() -> Int {
        return items.removeLast()
    }
}

This a just a basic stack struct. It's a struct that holds integers and allows you to both push and pop items out of it. It's nothing special. But what sucks is that if we implement our stack in this way we'll only ever be able to handle integers!

Here's how we would use this stack:

var myIntegerStack = IntStack()
myIntegerStack.push(1)
myIntegerStack.push(2)
myIntegerStack.pop() // returns 2
myIntegerStack.pop() // returns 1

Now let's see what we can do by making this stack generic!

struct Stack<Element> {
    var items = [Element]()
    mutating func push(_ item: Element) {
        items.append(item)
    }
    mutating func pop() -> Element {
        return items.removeLast()
    }
}

My replacing instances of Int with Element and changing the struct's definition from struct IntStack to struct Stack<Element>, we've made our stack generic. Technically, we've made our stack generic over Element. Now we're not restricted to just using our stack with integers. Here's how we could use it now:

var myIntegerStack = Stack<Int>()
myIntegerStack.push(1)
myIntegerStack.push(2)
myIntegerStack.pop() // returns 2
myIntegerStack.pop() // returns 1

var myStringStack = Stack<String>()
myIntegerStack.push("A")
myIntegerStack.push("B")
myIntegerStack.pop() // returns "B"
myIntegerStack.pop() // returns "A"

But where would we use something like this? For one, generics are used all over Core Data. It makes sense, because we're using a lot of the same methods, functions, and classes over different entities. We could also use it in a messaging service where we could have queues that could each handle emails, text messages, and Facebook messages whose objects representing them each conform to a messaging protocol. That's just an idea that came up off the top of my head, and we're just touching the tip of the iceberg in regards to generics.

This is the first in a three part series that I'm writing about generics. Next time, we're going to cover generic methods and functions!

When Your Resized UIImage Doesn't Keep Its New Size

As it turns out there are quite a few ways to resize images in iOS, and if you're looking for a breakdown of ways to do it NSHipster has a great article on the different ways of doing it. This article is more about how I did it in an app I'm working on and one of the pitfalls that I ran into (and ended up debugging for a couple hours).

Here's the UIKit extension that I used originally:

extension UIImage {
    func resizeImageTo(newSize: CGSize) -> UIImage? {
        let hasAlpha = false
        let scale: CGFloat = 0.0
        UIGraphicsBeginImageContextWithOptions(newSize, !hasAlpha, scale)
        self.draw(in: CGRect(origin: CGPoint.zero, size: newSize))
        let scaledImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return scaledImage
    }
}

But I kept running into a very weird issue.

My app is using Core Data to store images, and as you do in Core Data I took my UIImage and turned it into a NSData object in my save method like so:

if let imageData = UIImageJPEGRepresentation(image, 0.6) {
    entry.image = imageData as NSData
}            

But I noticed something very interesting, and that was that my images were still quite large. When I hopped into LLDB to do some poking around I noticed that when I created a UIImage instance from the NSData object the size property of the UIImage had the same size values as the original image directly from the camera, pre-resize. It made no sense to me at first. When doing a container dump of my application I could see the image files and they were at full resolution.

After more poking around, I noticed that the scale value of the resized UIImage was set to 3.0 while the new UIImage loaded from the NSData object had a scale value set to 1.0. That's when it clicked.

According to Apple's UIGraphicsBeginImageContextWithOptions documentation on the scale option:

The scale factor to apply to the bitmap. If you specify a value of 0.0, the scale factor is set to the scale factor of the device’s main screen.

I'm doing the majority of my development on an iPhone 7 Plus, whose default scale factor is set to 3.0. Checking UIScreen.main.scale in LLDB proved that to be true.

My modified code looked like this, and if you're running into the same issue of your images having a different size after using UIImageJPEGRepresentation or UIImagePNGRepresentation make sure you're passing UIGraphicsBeginImageContextWithOptions the proper scale option!

extension UIImage {
    func resizeImageTo(newSize: CGSize) -> UIImage? {
        let hasAlpha = false
        let scale: CGFloat = 1.0
        UIGraphicsBeginImageContextWithOptions(newSize, !hasAlpha, scale)
        self.draw(in: CGRect(origin: CGPoint.zero, size: newSize))
        let scaledImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return scaledImage
    }
}

After changing the scale option to 1.0, both the resized UIImage and the one I loaded using the NSData as a test both had the same scale value and therefore the same size values.

It's a small gotcha, but knowing that those two functions multiply your image's size by its scale will save you a ton of time when you're trying to resize your images. Hopefully it'll also help you get a small jump on your app's performance.

Review: 360iDev

slack-imgs

Have you ever been to one place in particular and realized that you're not the only person like yourself in the world? That's what 360iDev is like.

I got the opportunity to go to 360iDev when a friend of mine named Shane (who I met through my local CocoaHeads group, he help start a company called echo1612. Go throw him a bunch of money because he's a great guy) was able to get me a ticket almost last minute. Getting together with over 250 like-minded developers is one of the best things you can do for your programming career.

If it weren't for 360iDev, this blog wouldn't exist. I listened to two awesome people give two different talks, Soroush Khanlou on finding your place on the internet and Tammy Coron on if you can learn something, you can teach that thing. These two amazing people inspired me to go forth and do something that I've been actively putting off for over 5 years now just because of the thought battles that go on in our heads ("I'm not good enough", "I don't know enough", etc).

Going to 360iDev also taught me things that I needed to know more about such as iOS security principles, building UI in code, how to be an effective part of code reviews and more. I'm going to cover some of what I've learned in future blog posts. Those are topics that I had a lot of questions on because the answers are sometimes hard to find on the internet.

One of the most freeing things I heard there was it's totally OK (and honestly, what you should do) to use a prepackaged solution for authentication in your apps. Whether you use something like Passport.js or Auth0, this is always a better route than building your own authentication solution. It's battle tested and has so many eyes looking at the code you can trust it's more secure. That doesn't mean you're less of programmer. It means you made a good decision to not waste your time on something that you shouldn't focus on. There's no shame in leaving your authentication system to cryptography professionals so you can focus on feature-building code.

This is all just the tip of the iceberg of why you should go to 360iDev next year. Tons of events, there will always be someone in the room who can learn from, FREE SODA, and interesting sessions all four days. And of course, the new friends you make.

I can't wait until next year!

P.S. Photo credit goes to Fuad Kamal who was taking pictures all throughout the event. Thanks, Fuad!

Bleeding players.

halo3_73756043_Medium

That's what is happening to Halo right now.

I've never been a huge Call of Duty player in my time playing video games. I played Modern Warfare on the PC back in the day and didn't touch Call of Duty until Ghosts came out and I had a new Xbox One that had a major lack of titles to play. I got Advanced Warfare after that, which came out (I believe) right after the Halo 5 beta. My only thought was:

The movement is just like Halo 5!

Which was partially true. There were boosters and it was a lot faster than Halo 3 which I was playing on The Master Chief Collection. But after a few weeks, I was back to playing Halo 3. When Halo 5 came out, it was all I played for a solid year and a half. I bought Black Ops III and played it for two hours. I bought Infinite Warfare and ranked up to level 30 or so but have mostly played Modern Warfare: Remastered. Even then, Halo 5 never left my Xbox and I would always go back.

But now I'm not so sure.

Halo 5 is bleeding players. Not only has 343 not listened to a lot of user requests causing end users to switch from Halo to other major eSports titles, the pro users are seeing this and planning on switching to Call of Duty when WWII is released. It took them over a year to remove automatic weapons from competitive play which makes absolutely no sense.

I'm not abandoning Halo entirely. I love Halo a lot, but haven't played it in a few weeks. I'll be picking up a copy of WWII upon release and putting some time into it.