The right place to call .removeObserver for NSNotificationCenter = Swift deinit()? - swift

I've read a lot of suggestions for the right place to call .removeObserver for NSNotificationCenter since viewDidUnload is not an option.
I was just wondering if the new deinit() in Swift would be a good choice?
-nick

It really depends on the role of the class where you subscribe to NSNotificationCenter notifications. If you are subscribing in:
UIView
Then you should unsubscribe as soon as view gets invisible to the user. To save CPU cycles and not consume resources while user does not see the view.
UIViewController
Here it also depends on kind of action that you are going to perform in response to notification. If it is just a UI adjustment that you should unsubscribe as soon as view controller disappears from the screen.
You App Service layer
Here it is OK to have .removeObserver inside deinit(). however even here I tend to suggest you to be more explicit about when you subscribe and unsubscribe from NSNotificationCenternotifications and put them in start and stop methods of your service.

If you were previously calling removeObserver in viewDidUnload/dealloc/deinit, then starting with iOS 9.0 and macOS 10.11, you don't need to call it anymore:
If your app targets iOS 9.0 and later or macOS 10.11 and later, you don't need to unregister an observer in its dealloc method.
source: https://developer.apple.com/documentation/foundation/notificationcenter/1413994-removeobserver

Related

Difference between SceneDelegate and AppDelegate

In my SwiftUI project I see AppDelegate file as well as a SceneDelegate file.
What are the differences between them?
For example between the methods in SceneDelegate
scene(_:willConnectTo:options:)
and in the AppDelegate
application(_:didFinishLaunchingWithOptions:)
The two files are meant to split the work by what is needed to run the app as a whole and what is needed for one "instance" that would support visibly running in the background. This would be something like configuring a database once, but displaying different sets of values by window.
You could think of them as the global and private versions. One is shared and the other is limited to the individual owner. In a way, they are exactly what you would expect by the names.
Multi-window support is happening
Next time you create a new Xcode project you’ll see your AppDelegate
has split in two: AppDelegate.swift and SceneDelegate.swift. This is a
result of the new multi-window support that landed with iPadOS, and
effectively splits the work of the app delegate in two.
From iOS 13 onwards, your app delegate should:
Set up any data that you need for the duration of the app.
Respond to any events that focus on the app, such as a file being shared with you.
Register for external services, such as push notifications.
Configure your initial scenes.
In contrast, scene delegates are there to handle one instance of your
app’s user interface. So, if the user has created two windows showing
your app, you have two scenes, both backed by the same app delegate.
Keep in mind that these scenes are designed to work independently from
each other. So, your application no longer moves to the background,
but instead individual scenes do – the user might move one to the
background while keeping another open.
Courtesy of https://www.hackingwithswift.com/articles/193/whats-new-in-ios-13
AppDelegate is responsible for handling application-level events(like app launch), application lifecycle, and setup.
SceneDelegate is responsible for handling what is shown on the screen (Windows or Scenes) and managing the way your app is shown.
scene(_:willConnectTo:options:) is the first method called in UISceneSession life cycle. This method will create a new UIWindow, set the root view controller, and make this window the key window to be displayed.
application(_:didFinishLaunchingWithOptions:) is called when the application is launched and where the application set-up is done. Earlier iOS 13, we might have used this method to configure the UIWindow object and assign a ViewController instance to the UIWindow object to make it display on the screen. From iOS 13, if your application has scenes, then AppDelegate is no longer responsible for handling this and is moved to SceneDelegate.
From: https://medium.com/#kalyan.parise/understanding-scene-delegate-app-delegate-7503d48c5445
Multiplatform
In addition to the answer of Abandoned Cart, Since Xcode 11, You have a new option called Multiplatform for choosing as a starting template. That's where you will only see a file contains:
#main
struct MyMultiplatformApp: App {
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
This is how the system knows where to start the code with #main (in Swift 5.3) and it contains WindowGroup that manages multiple windows of your app in all apple platforms. So you don't need the be worry about SceneDelegate and AppDelegate anymore.
If you need it to be like the old app delegate, for example when you want to use its methods, You should subscribe for corresponding notifications or use the UIAppDelegateAdapter wrapper as I described here

How do I tie up appDelegate to the rest of the app?

I am a relative beginner to iOS development, but I managed to get my app to do everything I want it to. However, I have some questions about tying the app up together.
The only code I have currently inside my appDelegate handles remote notifications; when I receive a remote notification I send out the alerts, messages, and so on to the user. I also generate notifications for the notification center which cause different methods to run inside different view controllers.
What about all the different functions in the appDelegate? DidEnterBackground, WillEnterForeground, etc.? My app starts on one view (view1), which creates an object (stream1), which has a method stopStream. I have buttons to start and stop the streams ([self.stream1 stopStream]). My question in, how do I call these methods to stop that particular instance of the object in one of the appDelegate methods? Do I need to create a notification for the notification center inside the appDelegate, and handle it triggering in the view? Or is there a simpler method? Or am I doing things completely wrong and not according to best practices?
Any help would be appreciated! Also a link to a guide about the architecture of apps, or a link to your favorite book about building apps in iOS would be great!
Your app delegate only needs to implement the various app delegate methods if the app delegate actually needs to do something with those events.
If a given view controller or other class is interested in the various app delegate notifications (such as enter background, or return to foreground, etc.), then the view controller or other class should register for the corresponding notification. See the docs for UIApplication for the different notifications.
Do not have the app delegate method post a custom notification.
All the methods you're looking for can be found listed here in the docs.
As for what to do about them thats definitely up to your app. It is best practice to handle at least going in and out of the background properly so at least use the methods for those and take the appropriate action in your app.
Its very common for apps to simply blast out NSNotifications like you mention. Its perfectly acceptable in most circumstances.

Where to register for applicationWillResignActive using UIStoryboard

Looking at the example in Beginning iOS 5 for persisting your application state, in the first viewController that is shown for the app, they register for applicationWillResignActive in viewDidLoad:. So that makes sense to me in that you register for that notification when your first view is shown.
I'm confused on whether you always do this, or where you typically register for this notification. Q1) Like do they register for this notification in this viewController so they can recreate this view? Q2) If so, do I do this for each viewController?
Q3) I'm using UIStoryboard and my first viewController is a UITabBarController. So do I register for the notification in the first tab's viewController?
I also have a singleton DataManager object that holds the data for the app if that helps anyone guide me in the right direction of where I should save my data. Thanks!
These methods are in the AppDelegate.m
- (void)applicationWillResignActive:(UIApplication *)application
{
/*
Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
*/
}
You can perform your actions here. You can however register to "listen" to that event in another view controller (like your example) but that is just to make it easier to send that event notification into that viewcontroller.
1) no, only to ensure that whenver this VC is loaded it will be able to listen to this event.
2) no, only for the ones you want to pass the even easily like this. However using the appdelegate.m and each's vc view did appear is better.
3) depends on the kind of data you want to save, but typically you create your own file and just save it to disk like in any other OS. ios gives you access to the "documents" folder of your app and each folder is used for something specific, read the documentation.

iOS-FBConnect - requests results crash the app if the delegate of them released

I'm developing an iOS app and views create a request for their data,
now if the user dismiss the view, it's released and when the FBConnect call:
if ([_delegate respondsToSelector:
#selector(request:didReceiveResponse:)]) {
[_delegate request:self didReceiveResponse:httpResponse];
}
the app is crashed...
Any solution for that case?
Thanks!
Try using a higher-level controller as delegate, e.g. the main view controller, or the app delegate itself. This way you will always be sure that that component will not be released while the app is running.
either retain the _delegate. Or release the caller (the one making requests) as well from _delegate's dealloc method.
Or if both the above solutions are not suitable, then put the protocol implementation somewhere else.If you post more details may be then people will be able to provide specific answer.

How to receive application wide events with multiview application

I am developing an iPhone application with multiviews (Nav controller), but i like to receive an event if user touches in any view of the view. I understand it can be done by subclassing application delegate? If that's true how can i do it? My requirement is, i like to receive an event as soon as user touches any where in any view within my application.
Thanks for your help and time.
Your reference to subclassing UIApplication will work. Read down through the comments and it covers a somewhat quirky IMO way to implement it (by having the AppDelegate be a subclass of UIApplication). Myself, I would create a separate class to be the UIApplication subclass, rather than having the app delegate do both jobs, but I see the merit of either way.
That said, this is a very large and unusual stick and may suggest a design failure. What problem are you solving with this?
A way to do it is to use a Singleton class (which acts as an observer/mediator), which the application is an example of, in which you have viewControllers subscribe to when they are intersted in the touch events of a certain view. When the touch occurs the Singleton class is informed of the event as a result it informs all subscribers to the event of the event.
Here is an example
#interface MyEventClass
{
-(void)TouchEventDidOccur;
-(void)subscribeToTouchEvent:(id)delegate selector(selector):sel
}
Above is the singleton class
now this is an example of what the view touchesBegan method might look like
-(void)touchesBegan...
{
[[MyEventClass sharedInstance] TouchEventDidOccur];
}
and how one would subscribe to the event
[[MyEventClass sharedInstance] subscribeToTouchEvent:self selector:#selector(receiveTouchEvent:)]
hope this helps
What's wrong with using notifications? If you have disconnected classes across your application, it's trivial to have them listen for a particular notification, then have your views or view controllers post that notification when a touch event happens. All of the observers will take action on the notification.