MVC in Swift 4 - Model's interactions with Controller - ios

I'm developing a mobile application in Swift 4, that needs to interact with an external device using Bluetooth LE connection.
Currently i'm using the Model-View-Controller pattern to implement the structure of the app, but i need a clarification about.
When i receive data from the bluetooth adapter, i store it inside the model. The Model talks to the Controller "posting" the changes using the notification center.
On the other side, the Controller (the owner of the model) write the modification back to the Model simply setting the property of it.
The problem is that, sometimes, i do not have the Controller ready(instantiated), so i can loose Model's update (in that moment i'm not ready to "observe" the updates from the Model).
The only way that i found to workaround this issue is to:
In the Controller viewDidLoad read the status of the Model using "getters" of the Model properties.
Register the Controller to observe the future Model updates.
This now is working fine, but what i would like to understand is if this is the correct behaviour of communication between a Model and a Controller.

You can create a variable for that model in the view controller.
For the variable, implement didSet and perform the operations that you want to perform in the view controller. You do not need to post the changes using notification center.
In viewDidLoad, you can get the data first time from the bluetooth adapter.
After that whenever you receive the updated data from the bluetooth adapter, update the model only. It will do the rest of the things for you.

Related

Keeping a WKWebView and it's UIViewController in the background running and accessible from multiple ViewControllers

Background: In order to make web requests to an API endpoint, I need to scrape a website and retrieve a token every 25-30 seconds. I'm doing this with a WKWebView and injecting some custom JavaScript using WKUserScript to retrieve AJAX response headers containing the token. Please focus on the question specifically and not on this background information - I'm attempting this entirely for my own educational purposes.
Goal
I will have different 'model' classes, or even just other UIViewControllers, that may need to call the shared UIViewController to retrieve this token to make an authenticated request.
Maybe I might abstract this into one "Sdk" class. Regardless, this 'model' SDK class could be instantiated and used by any other ViewController.
More info
I would like to be able to call the UIViewController of the WKWebView and retrieve some data. Unless I re-create it every 25 seconds, I need to run it in the background or share it. I would like to be able to run a UIViewController 'in the background' and receive some information from it once WKWebView has done it's thing.
I know there are multiple ways of communicating with another ViewController including delegation and segueing. However, I'm not sure that these help me keep the view containing the WKWebView existing in the background so I can call it's ViewController and have it re-perform the scrape. Delegation may work for normal code, but what about one that must have the view existing? Would I have to re-create this WKWebView dynamically each time a different model, or view controller, were to try and get this token?
One post suggests utilising ContainerViewControllers. From this, I gather that in the 'master' ViewController (the one containing the other ones), I could place the hidden WKWebView to do it's thing and communicate to the child view controllers that way via delegation.
Another post suggests using AppDelegate and making it a shared service. I'm completely against using a Singleton as it is widely considered an anti-pattern. There must be another way, even if a little more complex, that helps me do what I want without resorting to this 'cheat'.
This post talks about communicating between multiple ViewControllers, but I can't figure out how this would be useful when something needs to stay running and executing things.
How about any other ways to do this? Run something in a background thread with a strong pointer so it doesn't get discarded? I'm using Xcode 9.2, Swift 4, and iOS 11. As I'm very new to iOS programming, any small code examples on this would be appreciated.
Unfortunately, WKWebView must be in the view hierarchy to use it. You must have added it as a sub view of an on-screen view controller.
This was fine for me. I added this off-screen so it was not visible. Hidden attribute might have worked as well. Either way you must call addSubview with it to make it work.
There are some other questions and answers here which verify this.
Here is a way if you don't wish to use a singleton.
1- In the DidFinishlaunchingWithOptions, Make a timer that runs in the background and call a method inside the app delegate Called FetchNewToken.
2- In FetchNewToken, make the call needed and retrieve the new token (you can use alamofire or any 3rd library to make the call easier for you).
Up on successfully retrieving the token, save it in NSUserDefaults under the name upToDateToken
You can access this token anywhere from the application using NSUserDefaults and it will always be up to date.

How do notifications fit in iOS VIPER architecture?

I was looking at VIPER architecures and I was wondering where notifications would go in the app. I use Realm local database which has the ability to send notifications when models are updated. Do notifications get broadcasted from the INTERACTOR --> PRESENTER --> VIEW or does it go somewhere else?
In this scenario Realm would be used as a data service, providing data. Accordingly, such as service is best placed in the interactor.
Then, as you say, events from the interactor can be passed to the presenter and them to the view, where you might want to reload a tableView or some such task.
I tend to pass the Realm results from the interactor to the presenter where I expose a variable for the view to use and update this in the callback from the interactor.

Passing user data through view controllers [duplicate]

This question already has answers here:
Passing data between view controllers
(45 answers)
Closed 8 years ago.
I'm making a basic app that allows user login.
I wanted to know the general practice of passing user data between view controllers. After a user is authenticated, is it generally acceptable to pass their data through view controllers?
For example, user A is logged in and authenticated. User A wants to "create a event", to be able to save that the user is hosting this event, I would have to store the users ID on the event as host and I would need access to his UID. Would you save the users ID after login and keep passing it in to every view?
I am using Firebase as my backend if that helps.
You should learn about a thing called "segues". It is the primary mechanism to transition between views in ios.
Here's a good tutorial(no personal affiliation, btw)
http://makeapppie.com/2014/07/01/swift-swift-using-segues-and-delegates-in-navigation-controllers-part-1-the-template/
haven't used firebase, but if you are passing event data from scratch by yourself you would do 4 things.
would declare the var in the target controller.
in the source controller you would fire off the function: performSegueWithIdentifier at the appropriate time.
that takes you to your prepareForSegue function (the contents of this func is like the last point of no return before you transition to the new controller). inside, create a var where the name of the type is the name of the target view controller.
use dot operators to access the variable you want to pass to and give it the appropriate value
Yes, best practice is to pass data between your view controllers as needed. You usually hook into the prepareForSegue method to accomplish that. Don't fall into the all-too-common practice of using (abusing, rather) your app delegate to maintain a bunch of global state. That is bad news. It is cleaner and more modular, in my view, to pass data down the view controller hierarchy, rather than having your view controllers reach back "up" and grabbing what they need.

Should I call my API from my model or controller?

My question is mostly related to an architectural or design pattern for hierarchical models in Objective C. For background my app is relatively simple. In general it talks to a web service to retrieve and display things a user can follow. When someone follows something, the thing they are following is conceptually stored for access later by posting to the web service.
I would like advice on where the logic should go to manage the interaction between the web service and the group of things a user follows.
For example, is it appropriate to create a model object like MyStuffModel with an array property named followedThings that holds references to AThingModel objects? And if so, would the logic for refreshing from the web service, etc be written and executed in the model?
Potential code example
#interface MyStuffModel : NSObject
#property (nonatomic, strong) NSArray *followedThings;
- (void)refreshAllFollowedThingsFromWebService;
#end
#implementation MyStuffModel
- (void)refreshAllFollowedThingsFromWebService
{
//call my API client (built on AFNetworking), get back a response
//populate followedThings, notify a view controller, etc
}
#end
Or, should I not have a MyStuffModel object and manage the calls to my web service by calling my API client directly from a view controller?
In your experience, which approach is desired? Or is there another way?
I would do all of the networking from within the model. Here's an outline of how all the pieces fit together
the controller tells the model which items to follow
the model forwards that information to the server
when the server has new information, it uses APNS to notify the model
the model requests the new information from the server
after the data transfer is complete, the model uses NSNotificationCenter to inform the controller that new information is available
the controller reads the information from the model
the controller updates the view with the new information
Using Apple's Push Notification Service (APNS) allows your server to notify your app when new data is available. This helps reduce network traffic since your app doesn't have to constantly poll the server to determine when new data is available. If you aren't familiar with APNS, there's one very important feature of the service that you need to be aware of (since it seems to be a point of confusion for many new users). The service only guarantees delivery of the last message sent. So, for example, if the server gets 10 new items for a particular device, and sends 10 notifications to the device while the device is either off or in a tunnel, then the service is only guaranteed to deliver the 10th message. The point is that you can't use APNS to send any data from the server to the device, since some messages may be lost. You should only use APNS to notify the device that data is available.
I always create model classes (and interfaces, no idea if thats applicable in ObjectiveC).
The model is in many cases a view of the database backend.
Your model class should hide the database access and provide a simple interface, for example using a addNewFollower method. This method should then (optionally do sanity checks) and persist this to the database backend.
This approach allows you to easily replace your database integration without touching the service layer at all. For example using an in-memory mock database for testing.
I always create simple "dumb" objects for models, as they model the data, nothing more. If you're doing networking/api calls, I'd create a separate set of classes that deal strictly with API calls and utilize your models as the interchange data. Mixing data and functionality is always fishy to me.
Writing a clean, reusable, testable, and reliable API client, that can handle errors, parallel/serial calls, logging etc, requires quite a bit of code that really should be separated from your other application tiers. Data is just data, keep it clean, keep it simple.
The other thing is that some endpoints don't always return data exactly as it is defined in that 1 model where you are shoe-horning all of your code.
I wouldn't put it in the controllers either, I personally always create a different set of classes that can be used specifically for API calls, which also throw their own exceptions, handle serialization/de-serialization etc.

What is the canonical design pattern/construct in iOS when a model should start some activity shortly after starting?

The high level design of my app consists of the App Delegate being the owner of the model which is created in didFinishLaunchingWithOption and then the app delegate passes a reference to the model to any controller class that needs to use it.
On app launch my app needs to call home to a server and download some content. This must be something common done by many apps, my question is what is the standard way of doing so, in particular which object and at at what point should be responsible for instructing the model to connect to the server? Lets assume there is a function on the model called CallHome() implemented asynchronously using NSURLConnection which can notify interested classes when complete.
Where should I perform this:
1) Could it be done in didFinishLaunchingWithOptions?
2) If didFinishLaunchingWithOptions should execute and return before the model executes CallHome() then which class should call CallHome()? Can the AppDelegate do this? If so where?
3) Could the model invoke CallHome() itself, if so when?
4) Or is this actually the job of a controller? If so should it be the root controller?
5) However what if the root controller doesn't need a reference to the model otherwise? So does that imply it should be another controller?
What is the recommended approach for the high level design for this functional requirement?
Many thanks.
you should make any server requests not before first view controller's viewDidAppear you can trigger your web service request in viewDidAppear of first view controller.
the reason behind the scene is if you web service call is synchronous, it will block the main thread (your application ideally, should not block application's main thread) and hence on device your application will crash unexpectedly during launch and hence will be rejected by apple on submitting it for AppStore.

Resources