This presentation is in two parts. The first part goes over how I refactored the Jukely app to have better separation of concerns by breaking up the controller into a "Storage" (aka Adapter, Repository) class and a "Layout" class. This technique worked very well for me, and resulted in cleaner code, more testable classes, and controllers that were easy to understand.
I also present MotionKit, which is a gem that is designed to fulfill that "Layout" role. You can design and update your views very easily using MotionKit, and it can be used on iOS, OS X, and we already have Android support on the way!
MotionKit was written by me and Jamon Holmgren.
3. Yes, there are models, fetched and
created by the controller
Yes, views, too. The controller makes
em!
API Queries, UI, animations,
network availability, login status, UI
events,
ticket purchasing, Facebook login, caching,
scrolling updates, image downloading and processing,
search filters, recommendations, notifications, sharing…
10. The benefits are many!
• Classes focus on one task
• Controllers don’t “do it all”
• Less code bloat all around
• Testable controllers
• Easier to add new features
• Easier to read and understand
11. – Colin T.A. Gray
“Don’t quote me on any of that.”
12. • Layout?
• Storage? WTF is that?
• Models & Queries?It’s your call.
Again, up to you.
There’s a gem for that. ;-)
14. • Animations
• Events
• Styles
• Imagine a controller and a view
got together and had an adorable
love child
• Move your UI code out of your
controller:
15. • Support for iOS and OS X
• Support for CALayer, NSMenu
• Frame and AutoLayout DSLs
• Add your own helpers just by
defining a class
16. class LoginLayout < MK::Layout # or < MK::WindowLayout
# or < MK::MenuLayout
view :username_field
view :submit_button # @layout.submit_button
def layout
background_color UIColor.blackColor
add UILabel, :login_label
add UIView, :login_container do
add UITextField, :username_field
add UIButton, :submit_button
end
end
end
17. def login_label_style
initial do # only apply when views are created
text 'Login'
backgroundColor UIColor.clearColor
font UIFont.boldSystemFontOfSize(40)
textAlignment UITextAlignmentCenter
layer do
shadowRadius 20
shadowOpacity 0.5
masksToBounds false
end
constraints do
width('100%')
center_x.equals(:superview)
end
end
end
18. # separate method to work with controller.topLayoutGuide
def add_constraints(controller)
constraints(self.view) do
origin [0, 0]
width.equals(:superview)
height.equals(:superview)
end
constraints(:login_label) do
below(controller.topLayoutGuide).plus(50)
# define top_margin: 50
# below(controller.topLayoutGuide).plus(:top_margin)
end
end
19. MotionKit Extensions
def label_style
frame from_top(:container, width: 200)
frame below(:button)
frame left_of(:other_label)
x 0
y 0
right 320
bottom '100% - 8'
end
Frames
21. MotionKit Extensions
NSMenu
class MainMenu < MK::Menu
def layout
add 'File' do
add 'Open', action: 'open:', key: 'o'
add 'Close', action: 'close:', key: 'w'
add 'Foo', :foo_menu
add 'Bar', :bar_menu do
add 'Baz'
end
end
end
end
22. MotionKit Extensions
def label_style
autoresizing_mask :pin_to_top
layer do
backgroundColor UIColor.blackColor.CGColor
end
title 'Send'
title 'Done', state: UIControlStateDisabled
portrait do
frame [[0, 0], [100, 100]]
end
landscape do
frame [[20, 0], [140, 100]]
end
end
25. MotionKit::Events
Decouple your UI events
class LoginLayout < MK::Layout
def login_button_style
target.on :touch do
trigger(:login, username_field.text.to_s,
@password_field.text.to_s)
end
end
end
class LoginController < UIViewController
def viewDidLoad
super
@layout = LoginLayout.new(root: self.view)
@layout.on :login do |username, password|
handle_login(username, password)
end
end
end
27. – Colin T.A. Gray
“Oh yeah, Jamon I forgot to tell you.”
28. class LoginLayout < MK::Layout
view :username_field
view :submit_button
def layout
add Android::Widget::LinearLayout, :login_container do
orientation VERTICAL
add Android::View::TextView, :username_field
add Android::View::Button, :submit_button
end
end
def submit_button_style
text 'Login'
end
end
MotionKit on Android
29. Kill the Controllers!
• Controllers should do the minimum
amount of “paper pushing”
• UI and animations → Layout
• Talking to the API → Storage
• etc. (Misc Task → Misc Class)
30. DEMO
Example of a LoginController written with
Storage and Layout classes.
You can see some similar code here:
github.com/rubymotion/motion-kit-events
31. Colin T.A. Gray
Community Manager at HipByte
Engineer at Jukely
github.com/colinta
github.com/rubymotion/motion-kit
gem install motion-kit
github.com/colinta/motion-xray
gem install motion-xray
Notes de l'éditeur
These ideas are used throughout programming
Think of Sandi Metz’ “rules for developers” applied to a controller
I was a skeptic, but came to this style working on Jukely, and it’s been great
These ideas are used throughout programming
Think of Sandi Metz’ “rules for developers” applied to a controller
I was a skeptic, but came to this style working on Jukely, and it’s been great
We used Parse for the Models and Queries
UILabels and UIButtons for views
So where does everything else go?
Ends up looking like this
After refactoring, we can get to this situation
Also not, Layout between C & V, and “Storage aka Adapter” between C & M
MVC doesn’t provide enough “buckets”
Introducing: Meh kuh Vulcs
MVC doesn’t provide enough “buckets”
Introducing: Meh kuh Vulcs
MVC doesn’t provide enough “buckets”
Introducing: Meh kuh Vulcs
MVC doesn’t provide enough “buckets”
Introducing: Meh kuh Vulcs
“Don’t quote me on any of that.”
Layouts are not just “styling code dumping grounds”.
Share knowledge with the controller
Animations, events, and of course styles
Multiple platform support
Helpers can target any class
AutoLayout DSL has been really popular
Easy to add your own, or create a motion-kit-gem
Extend the MK::Layout class (or menu or window).
Ideally you WON’T need to create accessor methods
Code inside the block acts on the “current context”
Not really as much magic as you might think, other than the delegation stuff.
Check the README, it’s current the best source of information, and READMORE.md for some interesting information.
“Oh yeah, Jamon I forgot to tell you.”
“Speaking of a team of laser guided fly swatters…”