I'm looking for something similar to a Firebase completion block to confirm that my I've removed all Firebase callbacks before I switch to the next ViewController
ref.removeAllObservers()
let resultController = self.storyboard!.instantiateViewControllerWithIdentifier("Home") as! UIViewController
self.presentViewController(resultController, animated: true, completion: nil)
There is no "show me all registered observers" method in the Firebase API.
That said: if you are stuck with lingering observers, you probably registered them in a child node, but only called removeAllObservers on the top-level ref. You'll have to remove each observer from the exact ref/child where you initially registered it.
See the web docs for off:
Calling off() on a parent listener will not automatically remove listeners registered on child nodes, off() must also be called on any child listeners to remove the callback.
What makes you think that observers are not removed during removeAllObservers() call, that this operation is asynchronous and that you should wait for something? It's not necessary, it's synchronous operation.
Generally, do not remove observers with removeAllObservers(), because in this way you can remove observers added by another classes as well. It's better to keep array of FirebaseHandles somewhere and remove them one by one when not needed.
Detaching Blocks describes it.
Related
I'd like to monitor property value change of a managed object in Core Data for data integrity purpose (for example, if a specific property changes, another object in a relationship should be changed accordingly). I'm thinking to implement it using KVO and let the managed object observe its own property change. Below is my code.
extension Book {
override public func awakeFromInsert() {
super.awakeFromInsert()
observation = self.observe(\.date, options: [.old, .new]) { book, dateChange in
print("date is changed!")
}
}
override public func awakeFromFetch() {
super.awakeFromFetch()
observation = self.observe(\.date, options: [.old, .new]) { book, dateChange in
print("date is changed!")
}
}
}
(Note: the observation variable is a transient attribute of the managed object to keep a strong reference to the NSKeyValueObservation object.)
My question is what's the appropriate place to remove observers? Or is it necessary at all? I did try the above code and it worked fine. But I'm not sure if it just happened to work and may have potential issue when code becomes complex.
I have figured out the following after some research:
1) App should remove KVO observers before a NSObject is deallocated. For example, the doc says:
An object that calls this method must also eventually call either the removeObserver(:forKeyPath:) or removeObserver(:forKeyPath:context:) method to unregister the observer when participating in KVO.
Note: the doc is about addObserver(), not the API I'm using, but I think the idea is same.
2) The new KVO API in Swift removes the observer automatically when NSKeyValueObservation object is deinitialized (i.e., when it's out of scope or not referenced by others).
So I thought I should do this:
extension Book {
deinit {
observation = nil
}
}
But unfortunately that is impossible because XCode gave this error:
Deinitializers may only be declared within a class
So I wonder what's the usual way to do it? Could it be that, since the the observer and observee are same object, the underlying KVO framework code notices that observer object is also being deallocated, so it's OK without removing the observer explicitly?
Any suggestion will be much appreciated.
Update 1:
#pbasdf suggests using willTurnIntoFault. I google about it and find few discussions which indicate people using it this way. My main confusion: is fault a required a state before a NSManagemObject is deallocated? I don't find Apple doc says so (the doc doesn't have a state transition diagram).
EDIT: According to this post, when a NSManagedObjectContext is tore down, it turns all objects registered with it back into faults. If so, fault does always occur before deallocation.
BTW, while reading Apple doc, I also find this:
When Core Data turns an object into a fault, key-value observing (KVO) change notifications are sent to the object’s properties. If you are observing properties of an object that is turned into a fault and the fault is subsequently realized, you receive change notifications for properties whose values have not in fact changed.
That leads me to think using KVO with NSManagemObject is perhaps not a ideal approach because it is interfered by fault.
Update 2:
Since the observer and observee is the same object in my case, there is a much simpler approach than using KVO. That's defining a wrapper of property setter method and implementing all the logic in the wrapper. I'll use this approach.
That said, I still think my question is valid in general case where observer and observee are different objects.
Update 3:
#matt pointed out that it's OK to not remove KVO observers since iOS11. See another discussion here and official doc here.
Relaxed Key-Value Observing Unregistration Requirements
Prior to 10.13, KVO would throw an exception if any observers were still registered after an autonotifying object's -dealloc finished running. Additionally, if all observers were removed, but some were removed from another thread during dealloc, the exception would incorrectly still be thrown. This requirement has been relaxed in 10.13, subject to two conditions:
The object must be using KVO autonotifying, rather than manually calling -will and -didChangeValueForKey: (i.e. it should not return NO from +automaticallyNotifiesObserversForKey:)
The object must not override the (private) accessors for internal KVO state
If all of these are true, any remaining observers after -dealloc returns will be cleaned up by KVO; this is also somewhat more efficient than repeatedly calling -removeObserver methods.
In my view controller I am calling a method to request data to populate my tableView and handle any notifications at viewWillAppear and also with a notification observer for UIApplicationDidBecomeActiveNotification.
This appears to cause problems when I am initially launching the app (not from the background) because my loadJSON method gets called twice, causing cellForRowAtIndexPath to crash as my data is changing.
Anyone have a suggestion on how this is typically handled?
You can test you loadJSON task is or not is executing before call it.
Or you can cancel privious loadJSON task before perform it.
I use global object to manage data, that I should download from different places.
My object (for example, named DataManager) has notifications, block-callbacks or delegate to notify listeners about data updating.
Also it has method to check his state, for example: isDownloading. If my DataManager more complex class, it has enum for states or many methods for any aspect.
Now I do not like to use Singleton for implementation of DataManager, I prefer to creating a property in AppDelegate to store instance of the manager inside.
I have this from either the Apple documentation or the swift book
When an instance gets deinitialized, you still have access to the
properties inside the instance and can manipulate them as needed
before the instance totally goes away.
I'm confused, do they mean when we for example do some mathematical action using the instances property in the deinit() method? or lets say when we print a property of type string that was part of a specific instance, also from the deinit() method?
If so, then is the deinit() method the only way to manipulate a property when it is being deinitialized?
if you have a swift class with a a var you know you have to clean up after because ARC can't free it (e.g. C memory), you can still do that in deinit. The pointers stored in the properties are still valid!
it isn't useful for much more though (ok end observing with the notification center or kvo) BECAUSE there is no guarantee WHEN deist is called. ONLY that it is called before deallocation [whenever that is]
deinit is called right before deallocation (when the retainCount reaches 0), so all your properties are still valid and you can print your string. You don't need to set properties to nil explicitly in deinit as that happens automatically.
This being said, most classes don't even need deinit implemented
Most of the time I used deinit to remove observer that the instance is registered to, post any notifications if needed, and things like that.
As far as I know, the deinit method gets called just before the instance gets deinitialized, to give you a final opportuninty to do whatever you need to do (cleanup, close a file, terminate a network connection, etc).
What the documentation says is that, at the time deinit is called your object has not been deinitialized yet (but will be very soon), so you still can (for the last time) access its properties.
I'm working with network request classes and I'm concerned about crashes. For instance, working with closures is really easy as you pass a callback method to a function:
// some network client
func executeHttpRequest(#callback: (success: Bool) -> Void) {
// http request
callback(true)
}
// View Controller
func reload() {
networkClient.executeHttpRequest() { (success) -> Void in
self.myLabel.text = "it succeeded" // NOTE THIS CALL
}
}
However, since the process that should execute the callback is async, when callbacks interact with container class element (in this case an UIKit class) it may be vulnerable to crashes in situations like
The user navigated to another View Controller while the async task was still executing
The user pressed the home button while the async task was still executing
Etc...
So, when the callback finally gets fired, self.myLabel.text might result in a crash, as the View Controller to whom self was refering could already be deallocated.
Up to this point. Am I right or do swift implement something internally so that this never happens?
If I am right, then here's when the delegate pattern comes in handy, as delegate variables are weak references, which means, they are not kept in memory if deallocated.
// some network client
// NOTE this variable is an OPTIONAL and it's also a WEAK REFERENCE
weak var delegate: NetworkClientDelegate?
func executeHttpRequest() {
// http request
if let delegate = self.delegate {
delegate.callback(success: true)
}
}
Note how self.delegate, since it is a weak reference, it will point to nil if the View Controller (who implements the NetworkClientDelegate protocol) gets deallocated, and the callback is not called in that case.
My question would be: do closures have anything special that makes them a good choice in scenarios similar to this one, rather than going back to delegate pattern? It would be good if examples of closures (that won't end up in crashes due to nil pointer) are provided. Thanks.
So, when the callback finally gets fired, self.myLabel.text might result in a crash, as the View Controller to whom self was referring could already be deallocated.
If self has been imported into the closure as a strong reference, it is guaranteed that self will not be deallocated up until the closure has been finished executing. That is, the view controller is still alive when the closure gets called - even if it's view is not visible at this time. Statement self.myLabel.text = "it succeeded" will be executed, but even the label will not be visible, it will not crash.
There is, though, a subtle issue which can lead to a crash under certain circumstances:
Suppose, the closure has the last and only strong reference to the view controller. The closure finishes, and subsequently gets deallocated, which also releases the last strong reference to the view controller. This inevitable will call the dealloc method of the view controller. The dealloc method will execute on the same thread where the closure will be executed. Now, that the view controller is a UIKit object, it MUST be guaranteed that all methods send to this object will be executed on the main thread. So, IFF dealloc will be actually executed on some other thread, your code may crash.
A suitable approach would require to "cancel" an asynchronous task whose result is no longer needed by the view controller when it is "closed". This, of course, requires that your "task" can be cancelled.
To alleviate some issues with your former approach, you might capture a weak reference of your view controller instead of a strong reference when defining the closure. This would not prevent the asynchronous task to run up to its completion, but in the completion handler you can check whether the view controller is still alive, and just bail out if it does not exists anymore.
And, if you need to "keep" an UIKit object in some closure which may execute on some arbitrary thread, take care that this might be the last strong reference, and ensure this last strong reference gets released on the main thread.
See also: Using weak self in dispatch_async function
Edit:
My question would be: do closures have anything special that makes them a good choice in scenarios similar to this one, rather than going back to delegate pattern?
I would say, closures are the "better" approach in many use-cases:
Delegates are more prone to issues like circular references than closures (since they are "owned" by an object, and this object might be captured as a variable in the delegate).
The classic use-case for closure as completion handlers also improves the "locality" of your code making it more comprehensible: you state what shall happen when a task finished right after the statement invoking the task - no matter how long that may take.
The huge advantage with closures versus regular "functions" is that a closure captures the whole "context" at the time when it is defined. That is, it can refer to variables and "import" them into the closure at the time when it is defined - and use it when it executes, no matter when this happens, and when the original "stack" at definition-time is gone already.
If I were you I would use closures since they are more convenient and flexible than delegation in this scenario.
Regarding the user navigating to other view controllers and the async operation still executing in the background you could keep a reference to those operations and whenever the user navigates away from the view controller you could cancel them.
Alternatively, you could verify if the view controller's view is visible before updating the UI:
viewController.isViewLoaded && viewController.view.window
Regarding the app entering background/foreground, you could pause/resume the operations by overridng the applicationDidEnterBackground and applicationWillEnterForeground or registering for the appropriate notifications: UIApplicationWillEnterForegroundNotification / UIApplicationDidEnterBackgroundNotification
I highly recommend you to use AFNetworking since it's API offers all the things I mentioned above, and much more.
I am making an object that goes to download stuff for all of my view controllers. The object is singleton instance and has a callback method with received data once the download is completed. It also has a delegate property so that it knows which object to call back to after the download is done.
There are multiple controllers that use this shared instance, and my question is how to call back to the correct view controller that requested the download.
My approach is to use delegation, but the problem is that since other view controllers are also its delegate, the download object could call back to every object and this will be hard to track.
I've worked on projects where people have attempted to use multiple delegates and it's basically a bad idea. The delegate pattern is about a 1 to 1 relationship between a class and it's delegate. Whilst it is possible to achieve some level of multiple delegation through switching the delegates in and out, it's more likely to lead to unpredictable behaviour and bugs.
My recommendation would be to change how you are thinking about this. You have two options as I see it:
Switch to an Observer pattern where you can register multiple observers which your main class can interact with. This is useful where your observers all implement the same protocol and where your main class wants to be aware of the observers and interaction with them.
Broadcast NSNotifications to indicate state changes and events. Here is a more decoupled approach because the main class does not need to know who is listening and does not directly interact with them. Other can start and stop being notified at their leisure. It also has the advantage that you do not need to create or implement a separate protocol. Instead you register the classes that need to know about changes with the NSNotificationCenter which in turns handles all the routing of notifications for you.
It actually sounds like the delegate pattern might not be the best approach here.
I would look into NSNotificationCenter instead.
The basic idea is that your singleton doing the net connection posts a notification (with something like postNotificationName:object:userInfo:) , saying that new data is available. Within this notification, you can pass a dictionary object (userInfo) that holds the data you've fetched, or info on what parts of your Model contain updated data.
Then, your other view controllers can register themselves to 'observe' these notifications by calling addObserver:selector:name:object:. Generally speaking, when a vc becomes visible I call addObserver, and removeObserver when it's being hidden or transitioned out.
Good luck!
Delegation doesn't seem like the right solution to this problem. How about requiring the requesting view controller to provide an object (its self) and a selector for you to call as a completion notification? Of course, you'll need a place to store that object and selector until the download completes. Hopefully you have (or could create) an object for this.
i recommend to use one of these ways
observer:
when use data that you want to inform other object are near to primitive ones.for example when you are using 'NSMutableArray' you can not inform the change in one of object by the standard implemented pattern at least you need to implement one for your self that is not reusable that much
Notification
when your interaction with destination object (those need to be inform) is in one-way.it means you don't need any acknowledge or other data back from them.
delegate
when there is one object to inform at each time step.
note:block use for success and fail is not a pattern to broadcast data its about to queue task when you don't know when they are finishing or failing like network operations
EDIT:
how to create notification | multi delegate issues and implementation
While I agree with most of the answers here, if you did actually want to achieve multiple delegates you could potentially declare an array of delegates and send messages to all delegates within that array. If your protocol has optional delegate methods you safely check using responds(to aSelector: Selector!) -> Bool before invoking (being mindful of memory management, as those delegates would be strongly referenced in the array). Again I do agree that multiple delegates is likely a bad architectural idea and using blocks or notification center would suit your needs better.
One approach, which works for me if you only have one other object to forward messages to is to create a forwardingDelegate This does not end up with issues of hard to debug ordering of delegates and it does not unnecessarily create a dependency on the other object. Keep in mind, if you have many objects then this might not be the best approach, it is mainly for one additional object but this could be extended to support an array of objects so long as there is one that receives the SDK and forwards it to the other objects [1]. Note that every method that is needed for the forwarded object needs to pass it along, even if it is not used by the forwarding object.
For example, if I need to forward the messages coming from the mapView delegate:
- (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated
{
// handle this object here.
if ([self.forwardingDelegate respondsToSelector:#selector(mapView:regionDidChangeAnimated:)])
{
[self.forwardingDelegate mapView:mapView regionDidChangeAnimated:animated];
}
// or handle this object here.
}
[self.forwardingDelegate mapView:mapView regionDidChangeAnimated:animated];
The forwarding property would be declared like this.
#property (nonatomic) id<MKMapViewDelegate> forwardingDelegate;
And the other object would adopt the protocol as if it were receiving the original message.
[1] The array approach for multiple delegates may get tricky because then you don't have as much control over what order the delegates get called, as was mentioned in other posts.