Liferay Screens typically receives entities from a Liferay instance as
[String:AnyObject]
, where String
is the entity’s attribute and AnyObject
is the attribute’s value. Although you can use these dictionary objects
throughout your Screenlet, it’s often easier to create a model class that
converts each into an object that represents the corresponding Liferay entity.
This is especially convenient for complex entities composed of many
attribute-value pairs. Note that Liferay Screens already provides several model
classes for you.
Click here
to see them.
At this point, you might be saying, “Ugh! I have complex entities and Screens doesn’t provide a model class for them! I’m just going to give up and watch football.” Fret not! Although we’d never come between you and football, creating and using your own model class is straightforward.
Using the advanced version of the sample Add Bookmark Screenlet as an example, this tutorial shows you how to create and use a model class in your Screenlet. First, you’ll create your model class.
Creating Your Model Class
Your model class must contain all the code necessary to transform each
[String:AnyObject]
that comes back from the server into a model object that
represents the corresponding Liferay entity. This includes a constant for
holding each [String:AnyObject]
, and initializer that sets this constant, and
a public property for each attribute value.
For example, the sample Add Bookmark Screenlet adds a bookmark to a Liferay
instance’s Bookmarks portlet. Since the Mobile SDK service method that adds the
bookmark also returns it as [String:AnyObject]
, the Screenlet can convert it
into an object that represents bookmarks. It does so with its
Bookmark
model class.
This class extends NSObject
and sets the [String:AnyObject]
to the
attributes
constant via the initializer. This class also defines computed
properties that return the attribute values for each bookmark’s name and URL:
@objc public class Bookmark : NSObject {
public let attributes: [String:AnyObject]
public var name: String {
return attributes["name"] as! String
}
override public var description: String {
return attributes["description"] as! String
}
public var url: String {
return attributes["url"] as! String
}
public init(attributes: [String:AnyObject]) {
self.attributes = attributes
}
}
Next, you’ll put your model class to work.
Using Your Model Class
Now that your model class exists, you can use model objects anywhere your Screenlet handles results. Exactly where depends on what Screenlet components your Screenlet uses. For example, Add Bookmark Screenlet’s Connector, Interactor, delegate, and Screenlet class all handle the Screenlet’s results. The steps here therefore show you how to use model objects in each of these components. Note, however, that your Screenlet may lack a Connector or delegate: these components are optional. Variations on these steps are therefore noted where applicable.
-
Create model objects where the
[String: AnyObject]
results originate. For example, the[String: AnyObject]
results in Add Bookmark Screenlet originate in the Connector. Therefore, this is where the Screenlet createsBookmark
objects. The following code in the Screenlet’s Connector (AddBookmarkLiferayConnector
) does this. Theif
statement following the service call casts the results to[String: AnyObject]
, calls theBookmark
initializer with those results, and stores the resultingBookmark
object to the publicresultBookmarkInfo
variable. Note that this is only the code that makes the service call and creates theBookmark
object. Click here to see the completeAddBookmarkLiferayConnector
class:... // Public property for the results public var resultBookmarkInfo: Bookmark? ... override public func doRun(session session: LRSession) { let service = LRBookmarksEntryService_v7(session: session) do { let result = try service.addEntryWithGroupId(LiferayServerContext.groupId, folderId: folderId, name: title, url: url, description: "Added from Liferay Screens", serviceContext: nil) // Creates Bookmark objects from the service call's results if let result = result as? [String: AnyObject] { resultBookmarkInfo = Bookmark(attributes: result) lastError = nil } ... } ... }
If your Screenlet doesn’t have Connector, then your Interactor’s
start
method makes your server call and handles its results. Otherwise, the process for creating aBookmark
object from[String: AnyObject]
is the same. -
Handle your model objects in your Screenlet’s Interactor. The Interactor processes your Screenlet’s results, so it must also handle your model objects. If your Screenlet doesn’t use a Connector, then you already did this in your Interactor’s
start
method as mentioned at the end of the previous step. If your Screenlet uses a Connector, however, then this happens in your Interactor’scompletedConnector
method. For example, thecompletedConnector
method in Add Bookmark Screenlet’s Interactor (AddBookmarkInteractor
) retrieves theBookmark
via the Connector’sresultBookmarkInfo
variable. This method then assigns theBookmark
to the Interactor’s publicresultBookmark
variable. Note that this is only the code that handlesBookmark
objects. Click here to see the completeAddBookmarkInteractor
class:... // Public property for the results public var resultBookmark: Bookmark? ... // The completedConnector method gets the results from the Connector override public func completedConnector(c: ServerConnector) { if let addCon = (c as? AddBookmarkLiferayConnector), bookmark = addCon.resultBookmarkInfo { self.resultBookmark = bookmark } }
-
If your Screenlet uses a delegate, your delegate protocol must account for your model objects. Skip this step if you don’t have a delegate. For example, Add Bookmark Screenlet’s delegate (
AddBookmarkScreenletDelegate
) must communicateBookmark
objects. The delegate’s first method does this via its second argument:@objc public protocol AddBookmarkScreenletDelegate: BaseScreenletDelegate { optional func screenlet(screenlet: AddBookmarkScreenlet, onBookmarkAdded bookmark: Bookmark) optional func screenlet(screenlet: AddBookmarkScreenlet, onAddBookmarkError error: NSError) }
-
Get the model object from the Interactor in your Screenlet class’s
interactor.onSuccess
closure. You can then use the model object however you wish. For example, theinteractor.onSuccess
closure in Add Bookmark Screenlet’s Screenlet class (AddBookmarkScreenlet
) retrieves theBookmark
from the Interactor’sresultBookmark
property. It then handles theBookmark
via the delegate. Note that in this example, the closure is in the Screenlet class’s Interactor method that adds a bookmark (createAddBookmarkInteractor
). Be sure to get your model object wherever theinteractor.onSuccess
closure is in your Screenlet class. Click here to see the completeAddBookmarkScreenlet
:... private func createAddBookmarkInteractor() -> Interactor { let interactor = AddBookmarkInteractor(screenlet: self, folderId: folderId, title: viewModel.title!, url: viewModel.URL!) // Called when the Interactor finishes successfully interactor.onSuccess = { if let bookmark = interactor.resultBookmark { self.addBookmarkDelegate?.screenlet?(self, onBookmarkAdded: bookmark) } } // Called when the Interactor finishes with an error interactor.onFailure = { error in self.addBookmarkDelegate?.screenlet?(self, onAddBookmarkError: error) } return interactor } ...
Awesome! Now you know how to create and use a model class in your Screenlet.