• Samsung VR for iOS

    We’ve released a new product at work today!

    Samsung VR is now available for iOS. There’s a huge amount of immersive video content available online and the barrier to creating has never been lower for both professionals and hobbyists. Samsung VR is the best way to present and discover immersive video, I hope you’ll enjoy using the app as much as I’ve enjoyed creating it!

  • Apollo + PromiseKit

    Today we’re looking at [the very cool] GraphQL and a popular iOS client library for interfacing with GraphQL servers. Being that the rest of the application in question is already chock-full of promises, it made sense to want an option for using promises rather than Apollo’s GraphQLQueryWatcher + callbacks. The good news is that Apollo has support for promises, the bad news is that they wrote it themselves.

    Love it when a framework recreates another popular library and we spend time writing plumbing like this. The simplicity of this little bit of code obscures how annoying this really is. Now with multiple declarations of the same class in this project, we have lots of compiler hinting and needless explicit module qualifications that could be avoided by not reinventing the wheel. If you’re creating a library for iOS and want to include Promise functionality, please use PromiseKit.

    Of course, the real answer is a set of concurrency primitives in Swift. Soon.

    import Apollo
    import PromiseKit
    
    extension Apollo.Promise {
        func pkPromise() -> PromiseKit.Promise<Value> {
            return PromiseKit.Promise(resolvers: { (fulfill, reject) in
                self.andThen({ (v) in
                    fulfill(v)
                }).catch({ (err) in
                    reject(err)
                })
            })
        }
    }
    
  • Real Screen Lock in High Sierra

    Glad to finally get Keychain Access out of my menu bar

    Finally.

  • UIBarButtonItem Sizing in iOS 11

    When setting UIBarButtonItem in previous versions of iOS I’ve been able to reliably control the size of buttons by using a UIButton initialized with a frame. In iOS 11 this has changed as UINavigationItem now [finally] uses AutoLayout.

    The easy solve for this, using SnapKit looks like:

    let button = UIButton()
    button.setImage(UIImage(named: "btn-img"), for: .normal)
    button.addTarget(self, action: #selector(buttonAction), for: .touchUpInside)
    let barItem = UIBarButtonItem(customView: button)
    
    barItem.customView?.snp.makeConstraints({ (make) in
      make.width.equalTo(22)
      make.height.equalTo(22)
    })
    

    And if you’re using vanilla AutoLayout:

    let button = UIButton()
    button.setImage(UIImage(named: "btn-img"), for: .normal)
    button.addTarget(self, action: #selector(buttonAction), for: .touchUpInside)
    let barItem = UIBarButtonItem(customView: button)
    
    let width = barItem.customView?.widthAnchor.constraint(equalToConstant: 22)
    width.isActive = true
    let height = barItem.customView?.heightAnchor.constraint(equalToConstant: 22)
    height.isActive = true
    

    Extra bonus: you can also safely connect your bar buttons to custom navigation item titleView’s to avoid buttons overlaying your title content. This is a great improvement to have in iOS 11 and should obviate the need for the UINavigationBar hacking of yore.

  • Swift 4 Codable with Alamofire & PromiseKit

    I’ve been really excited about Swift 4’s Codable since it landed earlier this year. Finally, now that the Xcode 9 GM is out, I’m ready to start converting the rather large Swift 3 project I work on day to day. Its full of the usual init?(dict: Dictionary<String,Any>) initializers you know and love.

    Converting our model classes to Codable has been a big win and allowed me to delete a lot of code, but my API functions based around Alamofire and PromiseKit immediately broke without the custom dictionary initializers.

    // The old
    func getFeed() -> Promise<FeedPage> {
        return Alamofire.request("https://null.info/feed").responseJSON().then { json in
            guard let jsonDict = json as? Dictionary<String, Any>,
                let feedPage = FeedPage(dict: jsonDict) else {
                    return Promise(error: NSError(domain: "com.samsung", code: -1, userInfo: [NSLocalizedDescriptionKey: "Server Error"]))
            }
            
            return Promise(value: feedPage)
        }
    }
    

    While it worked, this old way is kind of gross. It requires you to manually initialize each object and to specify its type twice: once in the function signature’s return type (Promise<FeedPage>) and again when deserializing the response (FeedPage(dict:jsonDict)).

    Since Codable provides us a uniform interface for deserialization, we can clean this up in a rather nice way that will be reusable across projects. The same way Alamofire gives us the really nice responseJSON() for returning a dictionary, let’s create a responseCodable(), which could return any class or struct which conforms to Codable.

    extension Alamofire.DataRequest {
        // Return a Promise for a Codable
        public func responseCodable<T: Codable>() -> Promise<T> {
            
            return Promise { fulfill, reject in
                responseData(queue: nil) { response in
                    switch response.result {
                    case .success(let value):
                        let decoder = JSONDecoder()
                        do {
                            fulfill(try decoder.decode(T.self, from: value))
                        } catch let e {
                            reject(e)
                        }
                    case .failure(let error):
                        reject(error)
                    }
                }
            }
        }
    }
    

    This is a fairly routine use of generic types. The really cool bit is using it in practice. Since we already have a bunch of function signatures specifying the expected return type (in this case, a FeedPage), Swift can infer the generic type to use when calling responseCodable() based on the return type. Have a look:

    // The new
    func getFeed() -> Promise<FeedPage> {
        return Alamofire.request("https://null.info/feed", parameters: params).responseCodable()
    }
    

    This has allowed me to delete nearly 50% of the code in the API class and has turned out to be the really huge win in letting us delete boilerplate, error-prone code.