Giter Club home page Giter Club logo

loaders's Introduction

Carthage compatible Version License Platform

Simple μFramework for loading Storyboard and Xib files for iOS.

Loaders

Let's imagine:

You have Main.storyboard file with initial view controller and two other controllers with identifiers: "PageViewController", "PageDetailsViewController". You have to instantiate them programatically and all you need to do is to declare enum like that:

enum Main: String, Storyboard {
    case initialViewController, pageViewController, pageDetailsViewController
}

... and you can load view controllers:

let pageViewController = Main.pageViewController.load()  // type will be UIViewController

... or with type:

let pageViewController: PageViewController = Main.pageViewController.load() 

... and also you would like to write Unit Test which will check all the controllers are loading properly. So you write:

extension Main: CaseIterable { }

class AppTests: XCTestCase {

    func testMainStoryboard() {
        _ = Main.allCases.map { $0.load() } // [UIViewController] 
    }
}

Lucky you ;) You can do that with the Loaders.

Other possibilities with Storyboard

When you use single storyboard per view controller you can declare it:

enum Details: Storyboard, HasInitialController { }

Then you can instantiate controller like that:

_ = Details.instantiateInitialViewController() // UIViewController

Strong types view controllers

When you need typed initial view controller you have to specify typealias like that:

enum Details: Storyboard, HasInitialController { 
    typealias InitialControllerType = DetailsViewController
}

You can also declare strong type view controllers based on identifiers:

enum Main: Storyboard, HasInitialController {
    typealias InitialControllerType = MainViewController
    
    static var pageViewController: PageViewController { return load() }
    static var pageDetailsViewController: PageDetailsViewController { return load() }
}

then load:

_ = Main.instantiateInitialViewController() // MainViewController 
_ = Main.pageViewController // PageViewController
_ = Main.pageDetailsViewController // PageDetailsViewController

If you don't like computed property to work as a fabric you can use methods instead:

enum Main: Storyboard, HasInitialController {
    typealias InitialControllerType = MainViewController

    static func pageViewController() -> PageViewController { return load() }
    static func pageDetailsViewController() -> PageDetailsViewController { return load() }
}

then load:

_ = Main.instantiateInitialViewController() // MainViewController 
_ = Main.pageViewController() // PageViewController
_ = Main.pageDetailsViewController() // PageDetailsViewController

ControllerLoader & Loader<Controller: UIViewController>

Sometimes there is a need to pass the factory that creates UIViewControllers and create UIViewController later instead of passing UIViewController instance. For that you can use Loader struct or just ConrollerLoader

enum Main: Storyboard, HasInitialController {

    static var pageViewController: Loader<PageViewController> { return loader() }
    static var pageDetailsViewController: ControllerLoader { return loader() }
    
}

_ = Main.initialViewController.load()
_ = Main.pageViewController.load()
_ = Main.pageDetailsViewController.load()

or

enum Main: String, Storyboard {
    case mainViewController
}

let loader = Main.mainViewController.loader()
loader.load()

or

enum Main: String, Storyboard, ControllerLoader {
    case mainViewController
}

let loader = Main.mainViewController
loader.load()

Reusable Nibs

Loaders also provides a way to register and deque reusable views loaded from xib files. It works for UITableViewCell, UICollectionViewCell, UICollectionReusableView. The rule you has to follow is that the class name, xib file name and identifier has to be the same.

 enum FormCells: Nibs {
 
     static var firstTableViewCell: Reusable<FirstTableViewCell> { return load() }
     static var secondTableViewCell: Reusable<SecondTableViewCell> { return load() }
 }

then you can register them:

FormCells.firstTableViewCell.register(on: tableView)

and later dequeue:

let cell = FormCells.firstTableViewCell.dequeue(on: tableView, for: indexPath) // FirstTableViewCell

Note: It works exaclty the same for UICollectionView.

Modules

If you have storyboards or reusables in different module of your app you can simply enclose declaration in enum with the same name as module. You can still enclose your declaration by any enum for grouping purposes but please remember to not conflict it with any module in your app.

enum Storyboards { // there is no module 'Storyboards' in the app so it will use 'current' module for Main storyboard
    
    enum Main: String, Storyboard {
        case initialViewController, pageViewController, pageDetailsViewController
    }

    enum User { // there is module User in the app it will load storyboards 'Main' and 'Profile' from there
        
        enum Main: String, Storyboard {
            case initialViewController, userViewController, userDetailsViewController
        }
        
        enum Profile: Storyboard, HasInitialController { }
    }
}

Custom view from Nib

Creating custom view using xib files instead writing them by hand in code is great idea. It is simple but need some boilerplate and usually it is not obvious for beginers how to do it in proper way. Each developer who is using your custom view should have possibility to instantiate that view in storyboards but he also should be able to do it from the code. He also should see the custom view in storyboard properly instead of "white rectangles". Loaders provide simple mechanism for loading xib files to custom views corectly.

To make custom designable view you need to create Xib file with the same name as your custom class and set the 'File Owner' with that class to have all IBOutlets initialized properly (remember - do not set 'Custom Class' for the main view - set 'File Owner' only).

In your custom view you have to add two constructors and inside them you have to add "Xib file" by single line of code Nib.add(to: self`). Simple implementation may look like that.

@IBDesignable
class DesignableView: UIView {

    @IBOutlet private var label: UILabel!

    @IBInspectable var title: String = "title" {
        didSet {
            label.text = title
        }
    }

    override init(frame: CGRect) {
        super.init(frame: frame)
        Nib.add(to: self)
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        Nib.add(to: self)
    }
}

Summary

Loaders is a simple way to define all your storyboard's UIViewControllers and NIB reusables (UITableViewCell, UICollectionViewCell, UICollectionReusableView) in clean, declarative way. It brings autocomplete and compile time checking for storyboards and xib files.

loaders's People

Contributors

dgrzeszczak avatar gjurzak avatar

Stargazers

 avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.