I want to continue to update userLocation every 0.5s from viewController to anotherViewController!! I've tried using a segue but that only updates one, anyone know another method or how?
Thanks!
Sure.
Create a protocol. Let's call it MyLocationDelegateProtocol.
Give it a method to get location updates.
Have your anotherViewController implement the method, and add the MyLocationDelegateProtocol to the class definition. (These steps can be referred to as "making the class conform to the MyLocationDelegateProtocol".)
Give the view controller that will be sending out location updates a locationDelegate property. When you create the view controller, set it's locationDelegate property to your anotherViewController.
Write the location methods so that they check to see if the locationDelegate property is nil. If it's NOT nil, send location messages to the locationDelegate using the message(s) defined in the MyLocationDelegateProtocol.
Related
I have created all my views programatically and to the UIView I have created an extension. This extension is present in a different file called App+Extensions.swift
extension UIView {
func setupParentView() -> UIView {
//...
}
}
The setupParentView() gives me a view with my navbar and background colour. As the design is same everywhere I have used this function. This function is called everywhere in viewDidLoad. So, now in this function the navabar consists of points which need to updated every time the user has purchased/spent it.
So, now as this method is only called in viewDidLoad the function is not called again and the point value do not change in the navigation bar. So, how can I update the point value every time it is changed? I thought of using Combine, but this app will be available for iOS 12 users as well, and I am not using RxSwift, so any help?
Well ViewDidLoad won't get refreshed because your view is now in the stack hierarchy. Some override methods that do get called which have a relation to the view are viewWillAppear, viewDidDissapear, and viewDidAppear.
If your view is going back in forth and the point button needs to be updated everytime your view re-appears consider putting the "refresh" point number in one of the above methods.
Note if your sending info back and forth between two views its also best maybe implement a delegation pattern or an observer.
Use notifications.
In other words, have points be a property of a global object that lives off in "data space" as a singleton. Now just use a property observer so that whenever anyone changes that object's points property, it emits a notification through the NotificationCenter.
That way, any view or view controller that needs to update whenever the points property changes just has to register for that notification when it comes into existence.
[Basically, this is the mechanism, or one of the mechanisms, that you would be replacing or even using directly if you were using Combine or RxSwift.]
Create a custom view called NavBarView
This NavBarView has a property called point
var point = 0 { didSet { updateView() } }
You want to avoid singleton, single view object, so that not everything is coupled together.
You don't need RxSwift or notification to do this.
Let's assume I have an address book App.
So from the address list I now push to a detail view like so:
User taps on cell in the master list
Segue showDetail is invoked
In prepareForSegue: I set the model object contact of my ContactDetailViewController
viewWillAppear I add an observer for self.contact
So now when the contact object changes in the background, the detail view will automatically be updated.
In viewWillDisappear I remove this observer (I guess it's clean because it is symetrical).
However, viewWillAppear: is called after I set the contact. So should I setup the KVO differently or simply call my updateView function in viewWillAppear which is a bit stupid because I want to get rid of those calls with KVO in the first place.
When you call addObserver:... you want to include the option NSKeyValueObservingOptionInitial. This will cause KVO to send the equivalent of a didChangeValueForKey: notification (i.e. an "Initial" notification) in the same call that adds the observation. This should cause your view to update at that time.
i have a class RequestHandler that takes the requests for some ViewController and fetches data on the web asynchronously. In order to notify the ViewController, it implements a protocol and the ViewController is set as its delegate.
Now, this ViewController is a TableViewController, and when a row is selected, it pushes a second ViewController on the NavigationStack. This second (child) ViewController needs to use the RequestHandler too. How can i make it a delegate for the same RequestHandler instance? And how can i make sure it won't mess with the parent TableViewController once i go back to it?
The fact that both view controller would want the same request suggests a design error. The view controllers should display the current state of the Model. They should not directly deal with active network requests.
You should have some group of classes that represent your data. These are called the Model. View controllers should only care about the model while the view is onscreen. So a reasonable pattern looks like this:
ViewController registers for notifications of changes in the Model
ViewController updates view with current data from Model.
ViewController requests an update.
RequestManager (singleton) creates a new RequestHandler to process it.
When RequestHandler finishes, it tells RequestManager and is released.
RequestManager updates Model with new data
Model alerts registered observers that it has changed.
ViewController updates view with current data from Model.
Now it doesn't matter if the user is on this view, or has moved to another, or moves to another and comes back. In call cases, any time the model changes, the current view is updated.
If I understand you correctly, is the RequestHandler a class written by you, so you could allow it to take more than one delegates for the implemented protocol (just store the delegates in an NSMutableArray, so you can add reps. remove them as you need)
Now when the new view is created, you can just 'register' it to your RequestHandler. The same way if the view is going to be closed, you could/should deregister it from your RequestHandler.
I have a view controller which gets an NSObject conforming to a protocol and then displays a view with the object's properties.
The question : How can my controller know that a property of this object has been modified and then refresh the view ?
Thanks a lot
Thierry
There are three ways of doing this:
Have the object call a method in the controller in response to an event e.g. a user clicking the button. This is usually done using an IBAction.
Set the controller to be the delegate of object e.g. a UIWebView sends a message to its delegate when it finishes loading a page.
Use a notification. The object generates the notification and then one or more objects (including the controller) registers to listen for the notification. This is usually not used with interface elements although it can be.
I can't tell you more without more detail about the specifics of your project.
Your viewcontroller should conform to your .
In your model, all your set methods should trigger appropriate functions you define in your modelchangedprotocol.
This OO design pattern is also known as "Observer" design pattern.
I have a modal view controller that creates core data changes in it's own context, and when I click done, it saves the changes (that dispatches the merge changes notification), notifies the delegate and dismisses.
My problem is that I need the delegate to receive the message after my main context has merged with the changes of the editing context. I want the delegate call to take place on the next run loop but I'm having problems with object lifetimes. I've thought of the following:
Make call to [delegate performSelector:withObject:afterDelay:] however it seems that that message is not recognised. My delegate conforms to the NSObject protocol but that doesn't include the perform selector with delay.
Create a method in my view controller: informDelegateWithObject: that calls the delegate method, and call that method after a delay. I.e. [self performSelector:#selector(informDelegateWithObject:) withObject:.. afterDelay:..]. This could work, however, as my view controller is being dismissed, if the delay is several seconds then it would have been released from memory and wouldn't that cause a crash when it comes to invoking?
Create an instance of NSInvocation. I have thought about this, however, what is the lifetime of this object? If I create it using [NSInvocation invocationWithMethodSignature:] then wouldn't the NSInvocation object be autoreleased, and not be around for the next run loop? Let alone several seconds. And as my modal view controller is being dismissed and released, I can't store the invocation object in my view controller.
Any suggestions?
You should merge contexts into the delegate.
Say that you press Save into you modal controller: you will send a myViewController:didFinishSaving: to the delegate.
This delegate into myViewController:didFinishSaving: implementation will save, merge and dismiss the modal view controller.
I hope I have understood your problem.
Bye! :)
You might look at Apple's Core Data Books tutorial which works along the lines that muccy describes. Saving happens after the modal view is dismissed and control is returned to the parent view controller. The parent contains the update code and fires notifications required to merge changes (whether that happens in the delegate or elsewhere).
To question #1: performSelector:withObject:afterDelay: is defined in the NSObject class, not the NSObject protocol. Any object you are using is probably an instance of NSObject. You are probably referring to a compiler warning resulting from static type checking. (Technically, it's possible for an object that conforms to the NSObject protocol to not be an NSObject; NSProxy is one example. But any object you normally use will be an NSObject.) You can ignore this warning (in Objective-C, you can try to send any message to any object). Or, if you want, you can cast it to either id (which allows you to send any message without any warnings) or NSObject *.
To question #2: "if the delay is several seconds then it would have been released from memory" No, the documentation for performSelector:withObject:afterDelay: says "This method retains the receiver and the anArgument parameter until after the selector is performed."
You can also declare your delegate like this:
NSObject <MyClassDelegateProtocol> *delegate;
Then your delegate will also be an NSObject that conforms to your protocol.