Let's talk about
delegation pattern
first.
Delegation
means that some object instead of dealing
with some task, delagates it to some other object.
All code below does not need memorizing. It is just an example of how delegation works. We just need to understand the idea.
For example, you want a user to select a photo from his media library. You create ImagePicker object, and you show it to the user:
# this is not a real code
picker = ImagePicker.new
picker.show
ImagePicker is a third-party library, written by other people. It can
only help the user to select some images.
However ImagePicker does not know what to do with those selected images
- it
delegates
this to us. It means we need to specify
who
will process our images:
picker.delegate = current_screen
When the user selects some images, ImagePicker object will call
a delegate and will pass it selected images. Delegate's job here is
to process them.
Image picker would say to delegate: "there were some images selected.
Please figure out what to do with them".
In our example, to make delegate work,
we would need to create a method that would accept this images.
Method names are always specified in a
delegator
(an object that asks for a delegate). You can't figure out a name
by yourself - delegator will call a specified method only.
It would look
similar to this:
# this is not a real code
picker = ImagePicker.new
picker.show
picker.delegate = self
# this method will be called automatically by ImagePicker object,
# when images will be selected:
def images_selected(images, error: error)
if error
# show some error
else
# save images
end
end
Another example is application loading: user tapped on a Springboard on your app's icon, and iOS started to load it. When your app has been launched, the delegate will be called. iOS would say to delegate: "Hey, I just loaded an app, what are you going to do next?". Usually, we start loading application screens.
One more example: tables. We have a table with ten cells in it. For example, this is a table with some of the user's contacts. When we create a table, we tell it that our current object will be a delegate for this table view:
@table = UITableView.new
@table.delegate = self
Then, when user will tap on a cell, table will call a method:
def tableView(table, didSelectRowAtIndexPath: index)
# you can process a tap here
end
Inside of this method, we can figure out which contact has been
selected, and open a new screen with this contact's info.
In other words, delegates are made to deal with results of some actions. The delegate will be called when images selected, when some file has been downloaded, when the app has been loaded, etc. Delegate object will decide what to do next - show some new screens, show an error, etc.
When you create a new iOS project, you will find an
Application Delegate file there. In Rubymotion it is a
/app/app_delegate.rb
file. App Delegate is the main delegate that is called when the app
is loaded or closed.
It will be called when push notifications
arrive, or when memory warning received, and in lots of other cases.
All available delegate methods can be found at Apple's docs: App Delegate Docs. For now, we are interested in
application:didFinishLaunchingWithOptions:
If you open
app_delegate
in
superapp
,
you will see that this method is already there. This is the main method
that called right when the app has been launched, and it waits for our
instructions. Rubymotion guys decided to add one screen for us already.
At the first glance code in the
app_delegate
may look scary. This is because it is a plain Objective-C converted to
Ruby.
We are going to learn how to make apps in Ruby-way, and not in Objective-C way. To do it, we need to install some gems first.
To start, let's add
ProMotion
gem to our
Gemfile
. ProMotion is an awesome library that helps us
to write real Ruby code. We will use their gem to create
Screens (in Objective-C you would call them UIViewControllers).
To add
ProMotion
to the app, just open your
Gemfile
,
and add next line:
gem 'ProMotion'
Then install it from your terminal with
bundle install
.
And now we can make our app delegate prettier. ProMotion developers upgraded default AppDelegate class a little bit, and we are going to use it as a base for our App Delegate. Let's remove all code inside the
application:didFinishLaunchingWithOptions:
class AppDelegate
def application(application, didFinishLaunchingWithOptions:launchOptions)
true
end
end
Try to launch the app now with
rake
.
You will see a boring black screen now.
Now we are going to replace the Objective-C-like code with a Ruby code. I hope you still remember what Inheritance is because we are going to inherit our AppDelegate from ProMotion's PM::Delegate class. We will also replace
application:didFinishLaunchingWithOptions:
on_load(app, options)
app_delegate.rb
should look like now:
class AppDelegate < PM::Delegate
def on_load(app, options={})
end
end
ProMotion's job here is to replace
- application:didFinishLaunchingWithOptions:
with the
on_load
method - the last one is easier to remember, to read, and to use. Also,
plain Objective-C method would require us always return
true
,
to make iOS know that everything is fine, and the app has been launched.
If you are interested how does it works: it is very easy.
We made our
AppDelegate
class derive from
PM::Delegate
,
which has this method implemented:
- application:didFinishLaunchingWithOptions:
.
When it is time, this method has been called, and it tries to
call the
on_load
method. If you are interested, here is ProMotion's source code that
does just this:
PM::Delegate
To know correct delegate names for Promotion's App Delegate, you can always visit their docs: ProMotion Docs on App Delegate
In this chapter, we've learned about Delegation Pattern. It has delegator - the object that is going to do some action for us. And delegate - the object that will be called when delegator will finish its task. Delegator will ask the delegate to process the result.
App Delegate is a place where you can customize application's behavior when it opens, closes, receives memory warnings, etc. This is the main file that starts your application.
For now, let's continue to the next chapter to learn about Rubymotion console.