-
@IBOutlet
@IBAction
linkage NOT compile time safe -
Nib/Xib/Storyboard merge conflict. 100% of time NOT guarantee to be safe
-
Storyboard
prepareForSegue
loadNib
breaks OOP. Views or ViewController always has NO self-documented schema (Constructor) to follow. -
Interface builder settings is not portable and cannot be replicated.
-
Interface builder settings is hard to find (compared to autocomplete in Swift), thus, super high learning curve.
-
Drag the auto-layout constaint is error-prone.
-
We are developer not designer
-
"Drag and drop" efficency is directly proportional to developer screen size
-
Xcode is very slow on rendering storyboard
-
Dynamic changing UI through User action is very common
-
Mixing Static(via IB) & Dynamic(via Code) makes project inconsistent and not predictable
-
Impossible to preview Dynamic UI
(DEMO) Let audience guess the result, safe to run / compile fail / crash app?
- delete
Button
in Interface builder - delete
@IBOutlet
- Try to rename
@IBOutlet
- delete function
@IBAction
- Copy & past IB Button (contains IBAction) to another view
Work Around to spot the human error (Automated UI Test/ 100% Test Coverage)?
OR Solve the Problem fundamentally?
- Consistent
- Predictable
- Codes are easy to add/ modify/ delete/ merge
- Easy to refactor
- Most of the human error can be captured by compiler
- 一個完全唔關事(識寫 Code 但唔識寫 iOS) 嘅人都可以輕鬆走入黎幫手
-
We use
RxSwift
consistently to handle all the events that emitted from a View.RxSwift
simplifies how we handle events (but high learning curve). -
We strictly decouple all views in a
DraglessUIKit
. All views are portable to other projects. -
We use
SnapKit
as our auto-layout engine (There are lots of choices you can pick instead of SnapKit). All dynamic/static layouts are consistently written in code and always be found inDraglessUIKit
. By the nature of human-writing instead of generated by Interface Builder, git merge-conflict is much easier to resolve. -
We think that "Save & Preview" is very important when developing a UI. Thus, We use Xcode +
@IBDesignable
(foundPreview.xib
). Also, all dynamic layout can also be previewed by changing theXXXView
state inprepareForInterfaceBuilder
-
We build extensions for
prepareForInterfaceBuilder
(IBHelper). i.e. drawing the boundaries of each view, recursively render all children view, 10 empty items for tableView to triggertableViewCell.prepareForInterfacebuilder
. -
We use
TypedViewControllerType
to bound developers strictly. By the protocol definition,XXXViewController
must ownXXXView
. AccessingtypedView
without any worries. No@IBOutlet
is needed anymore when you use -
We use
XXXViewControllerLaunching
protocol to provide a schema for launching the corresponding ViewController. All ViewController should own their ownlauncher
when it needs to launch other ViewController. (see in MainViewController) -
As the project has no
@IBOutlet
/@IBAction
, 100% Compile time safe. We heavily use Intellij Refactor features in Swift (Mostly for variable/function rename) -
We heavily use Intellij AppCode Live Template features to utilize this pattern as fast as possible.
This is our foundation. We had built lots of advance work based on this foundation but NOT appear in this project (i.e. How we utilize RxSwift, or declarative approach to handle view state, maybe on next sharing). But, I think this sample project can already provided enough insight to build a high quality and maintainable iOS Project.
If you like my IDE color style, visit https://github.com/gaplo917/IDE_Style