Ashley Arthur

Aug 08, 2017

Swinject Patterns

Swinject is a dependency injection framework for Swift which I've been using in some of my side projects recently. Having ran the app dev gauntlet with it, I've seen some nice patterns emerge that simplify setup code and promotes loose coupling between different features. Here's a non exhaustive list of some of benefits I've seen in my code.

Encapsulating new feature setup with Assemblers

For most features or area of functionality, we create a group of related entities that work together. For example implementing a new ViewController may require new delegate object as well.

class Foo: ViewController {
    var weak delegate: NewDelegateProtocol?

    // ....
}

To integrate this new vc, the existing code will need to instantiate the delegate and the data controller. This leaks implementation details into the rest of the system. Time for Assemblers! Here's what the protocol looks like:

protocol Assembly {
    public func assemble(container: Swinject.Container)
    public func loaded(resolver: Resolver)
}

And here's a simple implementation for our Foo View Controller

class FooAssembler: Assembly {

    func assemble(container: Container) {
        container.register(NewDelegateProtocol.self) { r in
            return NewDelegate()
        }

        container.register(Foo.self) { r in
            let vc = Foo()
            vc.delegate = container.resolve(NewDelegateProtocol.self)! 
        }
    }
}

An Assembler is a protocol which defines a single function Assemble. The Assembler's responsibility is to setup a container by registering factory callbacks. Why is this useful? We can augment existing containers with knowledge of Foo's setup requirements without leaking it to calling code, all they need to do is this:

mainContainer.resolve(Foo.self)!

Hoorah for encapsulation! Knowledge of the object graph is no longer required. As an added bonus, with features providing their own assemblers we can start conditionally including them, a step in the direction of feature flags.

Private Containers

Sometimes we want the feature to register factories but not have all of them exposed to anyone who includes the assembler. Going back to our example, maybe we don't want people accidentally instantiating our NewDelegate? We can use private internal containers:

class FooAssembler: Assembly {
    private let internalContainer = { 
        let container = Container()
        container.register(NewDelegateProtocol.self) { r in
            return NewDelegate()
        }
        return container
    }()

    func assemble(container: Container) {
        container.register(Foo.self) { r in
            let vc = Foo()
            vc.delegate = internalContainer.resolve(NewDelegateProtocol.self)! 
        }
    }
}

Here only Foo will be registered in the target container.

Containers as Abstract Factories

Obvious but worth mentioning: registering protocols instead of concrete classes in the container is an easy way to implement an abstract factory. Containers centralise the definition of the specified concrete class and allow you to easily pass around opaque references to objects.

Rules for unwrapping resolve calls

As I rely on other assemblers registering factories, we cannot always be sure if the resolve call will be fulfilled. Hence I try and stick to the following rules

  1. If the current assembler registers the factory then you can safely force unwrap
  2. If Type is specified in Core (i.e. never conditionally included), we can generally force unwrap
  3. Else it should be left as optional

Creating components at runtime

Not all objects are constructed at startup, for example we may need to construct a view controller and present it based on a user interaction aka the master-detail pattern. Instead of hard coding the next view controller into the master vc, we can express it as dependency that can injected in as required.

typealias ViewControllerFactory = () -> ViewController?

class Bar: ViewController {
    var nextVC: ViewControllerFactory?

    // ....

    func showDetail() {
        present(nextVC(), animated:true)
    }
}

class BarAssembler: Assembly
    func assemble(container: Container) {
        container.register(Bar.self) { r in
            var vc = Bar()
            vc.factory = { container.resolve(Spam.self) }               
            return vc 
        }
    }

Why does this matter? It decouples the master and detail vcs which allow for better modularity. We could easily add an alternative presented vc:

class BarAssembler: Assembly
    func assemble(container: Container) {
        container.register(Bar.self) { r in
            var vc = Bar()
            vc.factory = { container.resolve(Spam.self) }               
            return vc 
        }
        container.register(Bar.self, named:"AlternativeDetail") { r in
            var vc = Bar()
            vc.factory = { container.resolve(NewSpam.self) }                
            return vc 
        }
    }

A/B Test anyone? Or maybe increased testability? As a side note I prefer this approach as apposed to having an object take the container as a dependency as it keeps your vc decoupled from swinject itself.

Some of you maybe asking what about setting up the new view controller? That's easily taken care of:

typealias ViewControllerFactory = (Model) -> ViewController?

class Bar: ViewController {
    var nextVC: ViewControllerFactory?

    // ....

    func showDetail() {
        // ....
        present(nextVC(model), animated:true)
    }
}

class BarAssembler: Assembly
    func assemble(container: Container) {
        container.register(Bar.self) { r in
            var vc = Bar()
            vc.factory = { 
                nextvc = container.resolve(Spam.self)
                nextvc.data = $0
                return nextvc
             }              
            return vc 
        }
    }

This is very similar to the previous example but instead we now take in some input parameter to the ViewControllerFactory. What's great about this approach is within the callback we have knowledge of what concrete class we're setting up but returning to the outside world the more general ViewController class keeping things nice and opaque.

Is that all?

I'm still only scratching the surface of this great framework so I look forward to using it more over the coming projects. In my last: HueInspired I saw great improvements in modularity which helped improve overall testability (disclaimer: I like a good unittest). All I can say is go forth and swinject!

Apr 17, 2017

Autolayout Margin anchors vs Dimension anchors

Recently I was testing my custom table cells with dynamic type sizes and even though I didn't have any text present I noticed sub views changing sizes - intrigued, I investigated.

My cell content was ridiculously simple, just one view that filled the whole parent content view, so what could be going wrong? It turns out it was auto layout related. When Initially designing the layout I thought of two ways of creating the layout: match the height, width and centres of the parent view OR match horizontal and vertical anchors.

let constraints = [
view.centerXAnchor.constraint(equalTo: superview.layoutMarginsGuide.centerXAnchor),
view.centerYAnchor.constraint(equalTo: superview.layoutMarginsGuide.centerYAnchor),
view.heightAnchor.constraint(equalTo: superview.heightAnchor)
view.widthAnchor.constraint(equalTo: superview.widthAnchor)
]

let altConstraints = [
stackView.leadingAnchor.constraint(equalTo: superview.layoutMarginsGuide.leadingAnchor),
stackView.trailingAnchor.constraint(equalTo:superview.layoutMarginsGuide.trailingAnchor),
stackView.topAnchor.constraint(equalTo: superview.layoutMarginsGuide.topAnchor),
stackView.bottomAnchor.constraint(equalTo: superview.layoutMarginsGuide.bottomAnchor),
]

There is a difference though, and it's because I had opted to constrain anchors to the the margin guides. These are actually slightly offset from the edge by UIEdgeInsets and these change based on dynamic type sizes. I believe this is because table cells have the property self.contentView.preservesSuperviewLayoutMargins which means table view margin changes are inherited by the cell.

Ultimately this was a case of view hierarchies and layout constraints can appear the same to the user but there can be subtle differences when interacting with other subsystems.

On a simpler level, don't overlook your layout margins!

Apr 02, 2017

Creating Class level Properties in Python

So what happens when you want a computed class property in python?

Descriptors are invoked via the __getattribute__ so simply assigning a descriptor to a class level attribute won't do. Instead you need to create the class level property as a instance variable on the classes type object and rely on the fact attribute look up will eventually look there via the base classes __class__ attribute.

Obligatory meta class warning: you better be sure you really need todo this...

References

http://www.cafepy.com/article/python_attributes_and_methods/python_attributes_and_methods.pdf

posted at 00:00  ·   ·  Python

Mar 10, 2017

Use Unittests to Explore 3rd Party APIs

One of the ideas I've adopted recently is to use unittests to assert the contract between you and a 3rd party API. It's pretty normal to explore api usage in the REPL but by writing it formally as a series of tests you can record your findings and review them next time. Even better, you can tests your assumptions if the library ever changes.

FileIO is always a little platfrom specific, even with cross platform librarys like python's os.path. I was tasked recently with porting some tools to windows and found myself questioning some of my long held assumptions when working with file paths. The obvious question is what happens with all the backslashes?

Without futher ado:

posted at 00:00  ·   ·  Python

Nov 25, 2016

Restoring ViewControllers and their Data sources

The traditional flow for restoring view controllers in UIKit goes likes this:

  1. (Required) Assign restoration identifiers to the view controllers
  2. (Required) Tell iOS how to create or locate new view controller objects at launch time.
  3. (Optional) Encode current State for later restoration

Recreating the hierarchy of view controllers is indeed easy and mostly automated but a lot of the articles out there gloss over how to restore their dependencies (hint: Grabbing references to singletons in the VC’s decodeRestorableState method is not the correct answer!)

Normally you pass dependencies like a baton between controllers. When restoring a controller, the segue isn’t called and you get an ‘empty’ controller and its up to you to restore the dependencies. It turns out the data source can adopt the same state restoring protocol as the view controller and come along for the ride.

Assign restoration ids for dependencies

Normally as apart of the app launch you’ll have some code to initialise backing data sources for your view controllers. As a small extension to this routine, we also now have to give them an ID so that the VC’s can indirectly reference them on app restore.

The app delegate method willFinishLaunchingWithOptions is called after bootstrapping but before the restoration process so is a good place to register objects.

Tell iOS how to create or locate the dependency

Any registered dependency must conform to ‘UIStateRestoring’ protocol (UIViewControllers automatically conform to this) and allows you to define a restoration class

optional var objectRestorationClass: UIObjectRestoration.Type? { get }

If you return nil from this method, UIKIT assumes the app startup code recreated the dependency already and will be able to find it as you’ve registered it to a restoration id.

If you do specify a restoration class, it needs to define the following static method:

static func object(withRestorationIdentifierPath identifierComponents: [String], coder: NSCoder) -> UIStateRestoring?

It can return a reference to a global, init a new instance or return nil if no restoration is possible.

Restoring the Dependency as part of the Controller Decode Process

Now when you restore the view controllers state, any request to decode the datasources’s restoration id will simply be passed the registered instance. Voila! You can now reconstruct the VC’s dependencies.

The one draw back to this approach, as others have noted, is how it separates Controller Restoration and Dependency Restoration into two distinct phases. You’ve just lost your paddle if you’ve declared your dependencies as const. I think this hints at UIKits own opinion that controllers don’t actually own their datasources and so should be declared weakly.

References

posted at 00:00  ·   ·  Swift  iOS

Nov 20, 2016

Note to Unowned Self

Its easy to think that the answer to all closure woes is to just declare self unowned - no more reference cycles for me! However this is a very easy way to crash! Been there, done that, never again.

let me translate what 'unowned' means:

I am not the owner of this reference but I am 100% sure it will exist when I need it.

Said like that, you can see thats a pretty sizeable assumption!

A Weak reference, most of the time, will be a better bet because it makes you deal with possiblity of nil.

posted at 00:00  ·   ·  Swift  iOS

May 28, 2016

Python Bindings for TargetProcess

Where can you find them? In one of my side projects: tpapi - an unoffical python client for TargetProcess. It takes care of interacting with the REST api and returns nice model objects for you to interact with. Some useful features worth mentioning:

Transparent Pagination of Resource Requests

Every collection of entities is actually a generator which will lazily send http requests as needed. This way we can expose a standard iterator interface over paginated resources.

Nested Model Lookup

For resource or collection attributes we return an iterator over the correct class automatically so you can continue to chain queries or pluck values.

Theres also a gist showcasing usage: here

Apr 29, 2015

Testing Mac Gatekeeper

Gatekeeper on macOS guards against the execution and installation of applications from unknown sources. In order to pass this security check an application needs to be correctly signed which means its a good requirement to check before a release.

The key gotcha to watch out for when testing is to ensure the executable has been quarantined. By that I mean it has the ''com.apple.quarantine'' extended attribute present as Gatekeeper is triggered specifically at the first time you execute or install a quarantined file.

To verify the existence of the quarantine flag, you can show 'ls' output in terminal and look for the '@' at the end of the permission fields. Better yet you can use the 'xattr' command to show any extended attributes that exist on a file.

$ xattr /path/to/file

com.apple.quarantine

A programatic method to verify if the application's signature will pass gate keeper is to run the 'spctl' command.

spctl --assess --type install ./path/to/file

Spctl will exit zero on success or return one if anything failed.

Additionally you can check the actual signature use 'pkgutil' for futher details.

pkgutil --check-signature ./path/to/file
posted at 00:00  ·   ·  Testing  OSX

Mar 11, 2014

Python Descriptor Notes

  • Descriptors are any object that conform to the descriptor protocol __get__,__set__ and __del__. Properties are a common example
  • Descriptors are class level objects and you must use the obj reference passed to it in order to access the parent object.
  • This is because the descriptor protocol methods are invoked via an objects __getattribute__ - so be careful when overriding!
  • Weirdly hasattr returns false for testing if an class objects holds a specific property.

Example

References

www.docs.python.org/2/howto/descriptor.html

posted at 00:00  ·   ·  Python