RxSwift subscribe block not called - ios

I'm playing around with RxSwift and I'm stuck with a simple toy programm. My program essentially contains a model class and a viewcontroller. The model contains an observable that gets updated on the main queue after an asynchronous network call, the viewcontroller subscribes in viewDidLoad(). The AppDelegate initializes the model and passes it to ViewController and triggers the network request.
class GalleryModel {
var galleryCount: BehaviorSubject<Int>
init() {
galleryCount = BehaviorSubject.init(value:0)
}
func refresh() {
doAsyncRequestToAmazonWithCompletion { (response) -> AnyObject! in
var counter = 0
//process response
counter = 12
dispatch_async(dispatch_get_main_queue()) {
self.galleryCount.on(.Next(counter))
}
return nil
}
}
class ViewController: UIViewController {
#IBOutlet weak var label: UILabel!
var galleryModel: GalleryModel?
override func viewDidLoad() {
super.viewDidLoad()
galleryModel?.galleryCount.subscribe { e in
if let gc = e.element {
self.label.text = String(gc)
}
}
}
}
class AppDelegate: UIResponder, UIApplicationDelegate {
var galleryModel: GalleryModel?
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
//do amazon setup
galleryModel = GalleryModel()
if let viewController = window?.rootViewController as? ViewController {
viewController.galleryModel = GalleryModel()
}
return true
}
func applicationDidBecomeActive(application: UIApplication) {
galleryModel?.refresh()
}
The label gets updated only one, it shows "0". I expected the label to get updated twice, showing "0" after the first update and showing "12" after the second update after the processing of the network request. A breakpoint in the dispatch_async block gets hit, but it seems that galleryCount lost its observer. Anybody any idea what's happening or how to debug this?
Best

In case reads this anyone is interested. It was an refactoring error, after renaming variables I stopped passing the observable to the ViewController. Instead I created a new one... facepalm

Here are some useful snippets for subscribe in RxSwift (in Japanese)
For example to subscribe to different events:
let source: Observable<Int> = create { (observer: ObserverOf<Int>) in
sendNext(observer, 42)
sendCompleted(observer)
return AnonymousDisposable {
print("disposed")
}
}
let subscription = source.subscribe { (event: Event<Int>) -> Void in
switch event {
case .Next(let element):
print("Next: \(element)")
case .Completed:
print("Completed")
case .Error(let error):
print("Error: \(error)")
}
}

Clean and Build solved the problems for me

Related

transfer data with protocol

I try to decode weather api
this is my struct class weatherModal :
import Foundation
struct WeatherModel:Decodable{
var main:Main?
}
struct Main:Decodable {
var temp : Double?
var feels_like : Double?
var temp_min:Double?
var temp_max:Double?
var pressure , humidity: Int?
}
I am trying to learn protocols. So this is where a make api call manager class :
protocol WeatherManagerProtocol:AnyObject {
func weatherData(weatherData:WeatherModel)
}
class WeatherManager{
var weather : WeatherModel?
weak var delegate :WeatherManagerProtocol?
public func callWeather(city:String) {
let url = "http://api.openweathermap.org/data/2.5/weather?q=\(city)&appid=1234"
URLSession.shared.dataTask(with:URL(string: url)!) { (data, response, err) in
if err != nil {
print(err!.localizedDescription)
} else {
do {
self.weather = try JSONDecoder().decode(WeatherModel.self, from: data!)
self.delegate?.weatherData(weatherData: self.weather!)
} catch {
print(error.localizedDescription)
}
}
}.resume()
}
}
In my ViewController what I want to do is user write city name on textfield and If user clicked the process button print the information about weather.
class ViewController: UIViewController {
#IBOutlet weak var textField: UITextField!
var weatherManager = WeatherManager()
var data : WeatherModel?
override func viewDidLoad() {
super.viewDidLoad()
weatherManager.delegate = self
// Do any additional setup after loading the view.
}
#IBAction func processButtonClicked(_ sender: Any) {
if textField.text != "" {
weatherManager.callWeather(city: textField.text ?? "nil")
print(data?.main?.humidity) // it print nil
} else{
print("empty")
}
}
extension ViewController: WeatherManagerProtocol{
func weatherData(weatherData: WeatherModel) {
self.data = weatherData
print(self.data.main)
// in here I can show my data
}
}
When I clicked process button it always print nil. Why ? What am I doing wrong?
You seem not to understand how your own code is supposed to work. The whole idea of the protocol-and-delegate pattern you've set up is that the "signal" round-trips thru the weather manager on a path like this:
You (the ViewController) say weatherManager.callWeather
The weather manager does some networking.
The weather manager calls its own delegate's weatherData.
You (the ViewController) are that delegate, so your weatherData is called and that is where you can print.
So that is the signal path:
#IBAction func processButtonClicked(_ sender: Any) {
weatherManager.callWeather(city: textField.text ?? "nil") // < TO wm
}
func weatherData(weatherData: WeatherModel) { // < FROM wm
// can print `weatherData` here
}
You cannot short circuit this path by trying to print the weather data anywhere else. Stay on the path. You cannot turn this into a "linear" simple path; it is asynchronous.
If you do want it to look more like a "linear" simple path, use a completion handler instead of a delegate callback. That's what I do in my version of this same experiment, so my view controller code looks like this:
self.jsonTalker.fetchJSON(zip:self.currentZip) { result in
DispatchQueue.main.async {
// and now `result` contains the weather data, or an error
Even better, use the Combine framework (or wait until Swift 6 implements async/await).
You call to weatherManager.callWeather that start URLSession.shared.dataTask. the task is executed asynchronously, but callWeather return immediately. So, when you print data?.main?.humidity, the task did not finish yet, and data is still nil. After the task finish, you call weatherData and assign the response to data.

Embed Unity inside iOS in own ViewController

Using Unity 2019.3.0f3 and its Unity as a library feature I'm trying to embed a Unity project inside my iOS application.
Unity officially only supports full screen rendering. Nevertheless I'm looking for a way around that restriction.
In previous versions of Unity i successfully used swift-unity to do the integration. Within this approach it is easy to just get the View where Unity is rendering to (using UnityGetGLView()). I had no problems regarding stability or resources.
Using the new library approach, every time I try to access the UnityView, unity forces it's complete Window as keyWindow.
I tried accessing the UnityView in my own ViewController using
if let unityView = UnityFramework.getInstance()?.appController()?.rootViewController.view {
// insert subview at index 0 ensures unity view is behind current UI view
view?.insertSubview(unityView, at: 0)
}
But that immediately activates the complete unity-window and hides my parenting UITabBarController.
Trying to make the UnityFramework.getInstance()?.appController()?.rootViewController a child of my UITabBarController failed with the same result.
Furthermore it is not possible to add a child ViewController. Only adding subviews seems possible.
Does anybody know where that window-behaviour is located or how i can access the UnityView (or the RootViewController) and use it freely?
I found a solution to the problem based on this approach from the unity forum. Using this approach I'm able to use the UnityViewController as a child in my own TabBarController.
The approach is working for Unity 2019.3.0f3, but I'm not sure if it will work in future versions. It feels like Unity tries to actively prevent such use. Then again I found hints in comments in the library-code that would suggest that a modified ViewController-Hierarchy was at least contemplated e.g. in UnityAppController+ViewHandling.h. But the instructions are unclear and methods with the hinted names don't exist.
Solution
1. Create UnityEmbeddedSwift.swift
The official example App provided by Unity is a real mess. I ended up using the UnityEmbeddedSwift.swift from the linked forum post with additions for pausing. This class encapsulates all Unity-related functionality in one clean class.
//
// UnityEmbeddedSwift.swift
// Native
//
// Created by NSWell on 2019/12/19.
// Copyright © 2019 WEACW. All rights reserved.
//
//
// Created by Simon Tysland on 19/08/2019.
// Copyright © 2019 Simon Tysland. All rights reserved.
//
import Foundation
import UnityFramework
class UnityEmbeddedSwift: UIResponder, UIApplicationDelegate, UnityFrameworkListener {
private struct UnityMessage {
let objectName : String?
let methodName : String?
let messageBody : String?
}
private static var instance : UnityEmbeddedSwift!
private var ufw : UnityFramework!
private static var hostMainWindow : UIWindow! // Window to return to when exiting Unity window
private static var launchOpts : [UIApplication.LaunchOptionsKey: Any]?
private static var cachedMessages = [UnityMessage]()
// MARK: - Static functions (that can be called from other scripts)
static func getUnityRootViewController() -> UIViewController! {
return instance.ufw.appController()?.rootViewController
}
static func getUnityView() -> UIView! {
return instance.ufw.appController()?.rootViewController?.view
}
static func setHostMainWindow(_ hostMainWindow : UIWindow?) {
UnityEmbeddedSwift.hostMainWindow = hostMainWindow
let value = UIInterfaceOrientation.landscapeLeft.rawValue
UIDevice.current.setValue(value, forKey: "orientation")
}
static func setLaunchinOptions(_ launchingOptions : [UIApplication.LaunchOptionsKey: Any]?) {
UnityEmbeddedSwift.launchOpts = launchingOptions
}
static func showUnity() {
if(UnityEmbeddedSwift.instance == nil || UnityEmbeddedSwift.instance.unityIsInitialized() == false) {
UnityEmbeddedSwift().initUnityWindow()
}
else {
UnityEmbeddedSwift.instance.showUnityWindow()
}
}
static func hideUnity() {
UnityEmbeddedSwift.instance?.hideUnityWindow()
}
static func pauseUnity() {
UnityEmbeddedSwift.instance?.pauseUnityWindow()
}
static func unpauseUnity() {
UnityEmbeddedSwift.instance?.unpauseUnityWindow()
}
static func unloadUnity() {
UnityEmbeddedSwift.instance?.unloadUnityWindow()
}
static func sendUnityMessage(_ objectName : String, methodName : String, message : String) {
let msg : UnityMessage = UnityMessage(objectName: objectName, methodName: methodName, messageBody: message)
// Send the message right away if Unity is initialized, else cache it
if(UnityEmbeddedSwift.instance != nil && UnityEmbeddedSwift.instance.unityIsInitialized()) {
UnityEmbeddedSwift.instance.ufw.sendMessageToGO(withName: msg.objectName, functionName: msg.methodName, message: msg.messageBody)
}
else {
UnityEmbeddedSwift.cachedMessages.append(msg)
}
}
// MARK - Callback from UnityFrameworkListener
func unityDidUnload(_ notification: Notification!) {
ufw.unregisterFrameworkListener(self)
ufw = nil
UnityEmbeddedSwift.hostMainWindow?.makeKeyAndVisible()
}
// MARK: - Private functions (called within the class)
private func unityIsInitialized() -> Bool {
return ufw != nil && (ufw.appController() != nil)
}
private func initUnityWindow() {
if unityIsInitialized() {
showUnityWindow()
return
}
ufw = UnityFrameworkLoad()!
ufw.setDataBundleId("com.unity3d.framework")
ufw.register(self)
// NSClassFromString("FrameworkLibAPI")?.registerAPIforNativeCalls(self)
ufw.runEmbedded(withArgc: CommandLine.argc, argv: CommandLine.unsafeArgv, appLaunchOpts: UnityEmbeddedSwift.launchOpts)
sendUnityMessageToGameObject()
UnityEmbeddedSwift.instance = self
}
private func showUnityWindow() {
if unityIsInitialized() {
ufw.showUnityWindow()
sendUnityMessageToGameObject()
}
}
private func hideUnityWindow() {
if(UnityEmbeddedSwift.hostMainWindow == nil) {
print("WARNING: hostMainWindow is nil! Cannot switch from Unity window to previous window")
}
else {
UnityEmbeddedSwift.hostMainWindow?.makeKeyAndVisible()
}
}
private func pauseUnityWindow() {
ufw.pause(true)
}
private func unpauseUnityWindow() {
ufw.pause(false)
}
private func unloadUnityWindow() {
if unityIsInitialized() {
UnityEmbeddedSwift.cachedMessages.removeAll()
ufw.unloadApplication()
}
}
private func sendUnityMessageToGameObject() {
if (UnityEmbeddedSwift.cachedMessages.count >= 0 && unityIsInitialized())
{
for msg in UnityEmbeddedSwift.cachedMessages {
ufw.sendMessageToGO(withName: msg.objectName, functionName: msg.methodName, message: msg.messageBody)
}
UnityEmbeddedSwift.cachedMessages.removeAll()
}
}
private func UnityFrameworkLoad() -> UnityFramework? {
let bundlePath: String = Bundle.main.bundlePath + "/Frameworks/UnityFramework.framework"
let bundle = Bundle(path: bundlePath )
if bundle?.isLoaded == false {
bundle?.load()
}
let ufw = bundle?.principalClass?.getInstance()
if ufw?.appController() == nil {
// unity is not initialized
// ufw?.executeHeader = &mh_execute_header
let machineHeader = UnsafeMutablePointer<MachHeader>.allocate(capacity: 1)
machineHeader.pointee = _mh_execute_header
ufw!.setExecuteHeader(machineHeader)
}
return ufw
}
}
2. Modify AppDelegate.swift
Sets window and launch options needed by UnityEmbeddedSwift
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
UnityEmbeddedSwift.setHostMainWindow(window)
UnityEmbeddedSwift.setLaunchinOptions(launchOptions)
return true
}
3. Create RootTabBarController.swift
This class sets up the hierarchy.
It is important to use the UnityRootViewController right after calling UnityEmbeddedSwift.showUnity().
The Tab-Switching is not nice, but if it is missing Unity will pause (or freeze?) during loading. The timing seems to depend on the Unity-Projects loading time. It can be faster for small projects and needs more time for larger projects.
import UIKit
class RootTabBarController: UITabBarController, UITabBarControllerDelegate {
var unityNC: UINavigationController?
var nativeNC: UINavigationController?
override func viewDidLoad() {
super.viewDidLoad()
delegate = self
// start unity and immediatly set as rootViewController
// this loophole makes it possible to run unity in the same window
UnityEmbeddedSwift.showUnity()
let unityViewController = UnityEmbeddedSwift.getUnityRootViewController()!
unityViewController.navigationItem.title = "Unity"
unityNC = UINavigationController.init(rootViewController: unityViewController)
unityNC?.tabBarItem.title = "Unity"
let nativeViewController = UIViewController.init()
nativeViewController.view.backgroundColor = UIColor.darkGray
nativeViewController.navigationItem.title = "Native"
nativeNC = UINavigationController.init(rootViewController: nativeViewController)
nativeNC?.tabBarItem.title = "Native"
viewControllers = [unityNC!, nativeNC!]
// select other tab and reselect first tab to unfreeze unity-loading
DispatchQueue.main.asyncAfter(deadline: .now() + 0.2, execute: {
self.selectedIndex = 1
DispatchQueue.main.asyncAfter(deadline: .now() + 0.01, execute: {
self.selectedIndex = 0
})
})
}
// MARK: - UITabBarControllerDelegate
func tabBarController(_ tabBarController: UITabBarController, didSelect viewController: UIViewController) {
// pause unity if unity-tab is not selected
if viewController != unityNC {
UnityEmbeddedSwift.pauseUnity()
} else {
UnityEmbeddedSwift.unpauseUnity()
}
}
}
4. Modify Main.storyboard
Modify the storyboard to start with the RootTabBarController.
For anyone who is still interested in preventing the freezing, I am building on top of aalmigthy's answer:
You do not need to add a TabBar controller and switch between the tabs. All you need to do is:
Add the Unity view as a subview
Send the subview to back
Here's the modified ViewController class (no need for a tab bar):
import UIKit
class HybridViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
UnityEmbeddedSwift.showUnity()
let uView = UnityEmbeddedSwift.getUnityView()
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1, execute: {
self.view.addSubview(uView!)
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1, execute: {
self.view.sendSubviewToBack(uView!)
})
})
}
}

Where to trigger Loading in Clean Architeture Swift

Where is the correct place I should put the code that would trigger a loading to display in my app.
It is correct to do is on view? since it is displaying something on screen, so it fits as a UI logic
class ViewController: UIViewController {
func fetchData() {
showLoading()
interactor?.fetchData()
}
}
or on interactor? since it's a business logic. something like, everytime a request is made, we should display a loading. View only knows how to construct a loading, not when to display it.
class Interactor {
func fetchData() {
presenter?.presentLoading(true)
worker?.fetchData() { (data) [weak self] in
presenter?.presentLoading(false)
self?.presenter?.presentData(data)
}
}
}
same question applies to MVVM and MVP.
it is totally up to you . i am showing loading using an Observable .
in my viewModel there is an enum called action :
enum action {
case success(count:Int)
case deleteSuccess
case loading
case error
}
and an Observable of action type :
var actionsObservable = PublishSubject<action>()
then , before fetching data i call onNext method of actionObservable(loading)
and subscribing to it in viewController :
vm.actionsObserver
.observeOn(MainScheduler.instance)
.subscribe(onNext: { (action) in
switch action {
case .success(let count):
if(count == 0){
self.noItemLabel.isHidden = false
}
else{
self.noItemLabel.isHidden = true
}
self.refreshControl.endRefreshing()
self.removeSpinner()
case .loading:
self.showSpinner(onView : self.view)
case .error:
self.removeSpinner()
}
}, onError: { (e) in
print(e)
}).disposed(by: disposeBag)
You can use the delegate or completion handler to the update the UI from view model.
class PaymentViewController: UIViewController {
// for UI update
func showLoading() {
self.showLoader()
}
func stopLoading() {
self.removeLoader()
}
}
protocol PaymentOptionsDelegate : AnyObject {
func showLoading()
func stopLoading()
}
class PaymentOptionsViewModel {
weak var delegate : PaymentOptionsDelegate?
func fetchData() {
delegate?.showLoading()
delegate?.stopLoading()
}
}

REST API, Swift, Automatic Update

I'm currently struggling to find an easy-to-use programming approach/design pattern, which solves the following problem:
I've got an REST API where the iOS app can request the required data. The data is needed in different ViewControllers. But the problem is, that the data should "always" be up to date. So I need to set up a timer which triggers a request every 5-20 seconds, or sth like that. Everytime the data changes, the view needs to be updated (at the current viewcontroller, which is displayed).
I tried some stuff with delegation and MVC Pattern, but it's kind a messy. How is it done the right way?
In my current implementation I only can update the whole UICollectionView, not some specific cells, because I don't know how the data changed. My controller keeps track of the data from the api and updates only if the hash has changed (if data changed on the server). My models always holds the last fetched data.
It's not the perfect solution, in my opinion..
I also thought about models, that keep themselves up to date, to abstract or virtualise my Rest-API. In this case, my controller doesn't even know, that it isn't directly accessible data.
Maybe someone can help me out with some kind of programming model, designpattern or anything else. I'm happy about anything!
UPDATE: current implementation
The Controller, which handles all the data
import Foundation
import SwiftyJSON
import SwiftyTimer
class OverviewController {
static let sharedInstance = OverviewController()
let interval = 5.seconds
var delegate : OverviewControllerUpdateable?
var model : OverviewModel?
var timer : NSTimer!
func startFetching() -> Void {
self.fetchData()
timer = NSTimer.new(every: interval) {
self.fetchData()
}
timer.start(modes: NSRunLoopCommonModes)
}
func stopFetching() -> Void {
timer.invalidate()
}
func getConnections() -> [Connection]? {
return model?.getConnections()
}
func getConnectionsSlave() -> [Connection]? {
return model?.getConnectionsSlave()
}
func getUser() -> User? {
return model?.getUser()
}
func countConnections() -> Int {
if let count = model?.getConnections().count {
return count
}
return 0
}
func countConnectionsSlave() -> Int {
if let count = model?.getConnectionsSlave().count {
return count
}
return 0
}
func fetchData() {
ApiCaller.doCall(OverviewRoute(), completionHandler: { (data, hash) in
if let actModel = self.model {
if (actModel.getHash() == hash) {
//no update required
return
}
}
var connections : [Connection] = []
var connectionsSlave : [Connection] = []
for (_,connection):(String, JSON) in data["connections"] {
let connectionObj = Connection(json: connection)
if (connectionObj.isMaster == true) {
connections.append(connectionObj)
} else {
connectionsSlave.append(connectionObj)
}
}
let user = User(json: data["user"])
//model needs update
let model = OverviewModel()
model.setUser(user)
model.setConnections(connections)
model.setConnectionsSlave(connectionsSlave)
model.setHash(hash)
self.model = model
//prevent unexpectedly found nil exception
if (self.delegate != nil) {
self.delegate!.reloadView()
}
}, errorHandler: { (errors) in
}) { (progress) in
}
}
}
protocol OverviewControllerUpdateable {
func reloadView()
}
The model, which holds the data:
class OverviewModel {
var user : User!
var connections : [Connection]!
var connectionsSlave : [Connection]!
var connectionRequests : [ConnectionRequest]!
var hash : String!
...
}
And in the ViewController, I use it like this:
class OverviewVC: UIViewController, UICollectionViewDataSource, UICollectionViewDelegate, OverviewControllerUpdateable {
let controller = OverviewController.sharedInstance
override func viewDidLoad() {
super.viewDidLoad()
self.controller.delegate = self
self.controller.startFetching()
}
//INSIDE THE UICOLLECTIONVIEW DELEGATE METHODS
...
if let user : User = controller.getUser() {
cell.intervalTime = interval
cell.nameLabel.text = "Ihr Profil"
}
...
func reloadView() {
self.userCollectionView.reloadData()
}
}
You could use a Singleton object to fetch your data periodically, then post notifications (using NSNotificationCenter) when the data is updated. Each view controller dependent on the data would listen for these notifications, then reload UI based on the updated data.

Bind RACComand to UIViewController event

I'm implementing RAC with MVVM pattern in my project and now I came into a doubt.
I have many calls to the server, but all of them are associated to an UIButton and handled in my ViewModel; now I need to make a call to the server when the UIViewController is loaded. Before MVVM I just created a signal in the viewDidLoad method an voilá!, but I'm not sure if is ok to put this in the ViewController.
Now I don't know how to bind a RACSignal to an event in my ViewController, and worst of that, I'm not sure if that is the way following the MVVM pattern.
What I'm doing right now when I make a call to server coming from a user action(from a UIButton) is this:
ViewController*
self.someButton.rac_command = viewModel.executeSomeAction
//On success:
self.viewModel.executeLoginCompleted.skip(1).subscribeNextAs {
(isExecuting: Bool) -> () in
//Do something
}
//On error:
self.viewModel.executeSomeActionError.subscribeNextAs {
(error: NSError) -> () in
//Dd something
}
ViewModel*
var executeSomeAction: RACCommand?
var executeSomeActionError: RACSignal!
var executeLoginCompleted: RACSignal
executeSomeAction = RACCommand(enabled: combineValidationSignals) {
(any:AnyObject!) -> RACSignal in
println("ANY: \(any)")
return self.executeLoginRequest()
}
executeSomeActionError = executeLogin!.errors
executeLoginCompleted = executeLogin!.executing
How should I create a RACSignal or RACCommand when the UIView did load? Of course, following the MVVM pattern.
Thanks
You have two options. One more hacky than the other but easier to implement accross your app.
Option 1:
You can write an extension to UIViewController that uses associatedObjects to add a viewDidLoadCommand: RACCommand property to UIViewController. You then swizzle the viewDidLoad() method of UIViewController so that it executes your command on viewDidLoad():
extension UIViewController {
private struct AssociatedKeys {
static var ViewDidLoadCommand: String = "ViewDidLoadCommand"
}
var viewDidLoadCommand: RACCommand? {
get {
return objc_getAssociatedObject(self, &AssociatedKeys.ViewDidLoadCommand) as? RACCommand
}
set {
if let newValue = newValue {
objc_setAssociatedObject(
self,
&AssociatedKeys.ViewDidLoadCommand,
newValue as RACCommand?,
UInt(OBJC_ASSOCIATION_RETAIN_NONATOMIC)
)
}
}
}
func swizzled_viewDidLoad() {
self.swizzled_viewDidLoad()
self.viewDidLoadCommand?.execute(nil)
}
}
// In the appDelegate
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
// Override point for customization after application launch.
method_exchangeImplementations(
class_getInstanceMethod(UIViewController.self, "viewDidLoad"),
class_getInstanceMethod(UIViewController.self, "swizzled_viewDidLoad"))
return true
}
Option 2
You can just subclass UIViewController and implement the viewDidLoadCommandand call it in viewDidLoad()
class ViewControllerSubClass : UIViewController {
var viewDidLoadCommand: RACCommand?
override func viewDidLoad() {
super.viewDidLoad()
self.viewDidLoadCommand?.execute(nil)
}
}
Whichever method you choose all you have to do then is set the command in the your custom viewControllers init method and and it will get executed on viewDidLoad.

Resources