Get applicationDidFinishLaunching call in a View Controller. Parse not initialized yet - swift

I am trying to load data from Parse in my Initial View Controller. The issue is that Parse is initialized in my AppDelegate's didFinishLaunching so I need to wait until it is called before I attempt to load the data from Parse. What is the best way to get this notification in my view controller? Or would it be better to get the data in my AppDelegate?
All help is appreciated!

You can add an observer for the UIApplicationDidFinishLaunchingNotification inside your view controller viewDidLoad method:
NotificationCenter.default.addObserver(self, selector: #selector(didFinishLaunchingNotification), name: UIApplication.didFinishLaunchingNotification, object: nil)
Add your method to the view controller
#objc func didFinishLaunchingNotification(_ notification: Notification) {
// your code
}

Related

How to determine whether current view controller is active, and execute code if active

In my app, there is a ViewController.swift file and a popupViewController.swift file. Inside the app, when I open the popupViewController with storyboard segue as presentModally and then come back from popupViewController to ViewController with the code dismiss(), the methods viewDidLoad, viewWillAppear, viewDidAppear, ViewWillLayoutSubviews etc. nothing works, they execute just once and don't repeat when I go and return back. So, I want to execute the code every time when viewController.swift is active. I couldn't find a useful info in stackoverflow about this.
Meanwhile, I don't know much about notification and observers(if certainly needed), therefore, can you tell step by step in detail how to do that in Swift (not objective-c)? I mean how to determine if current view controller is active.
Edit: I am navigating from StoryBoard segue, presentModally. There is no Navigation Controller in storyboard.
I tried some codes but nothing happens. The point I came so far is:
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector:#selector(appWillEnterForeground), name:UIApplication.willEnterForegroundNotification, object: nil)
}
#objc func appWillEnterForeground() {
print("asdad") //nothing happens
if self.viewIfLoaded?.window != nil {
// viewController is visible
print("CURRENT VİEW CONTROLLER") //nothing happens
}
}
As mention in my comments, I don't use storyboards. There may be a way to create an unwind segue - or maybe not - but [here's a link][1] that may help you with a storyboard-only way of fixing your issue. A quick search on "modal" turned up 9 hits, and the second one starts going into details.
I'm thinking the issue is with what modality is. Basically, your first view controller, which properly executed viewDidAppear, is still visible. So it's effectively not executing viewDidDisappear when your second VC is presented.
You might want to change your concept a bit - an application window (think AppDelegate and/or SceneDelegate become active, where a UIViewController has a is initialized and deinitialized, along with a root UIView that is loaded, appears* and disappears*. This is important, because what you want to do is send your notification from the modal VC's viewDidDisappear override.
First, I find it easiest to put all your notication definitions in an extension:
extension Notification.Name {
static let modalHasDisappeared = Notification.Name("ModalHasDisappeared")
}
This helps not only reduce string typos but also is allows Xcode's code completion to kick in.
Next, in your first view controller, ad an observer to this notification:
init() {
super.init(nibName: nil, bundle: nil)
NotificationCenter.default.addObserver(self, selector: #selector(modalHasDisappeared), name: .modalHasDisappeared, object: nil)
}
required init?(coder: NSCoder) {
super.init(coder: coder)
NotificationCenter.default.addObserver(self, selector: #selector(modalHasDisappeared), name: .modalHasDisappeared, object: nil)
}
#objc func modalHasDisappeared() {
print("modal has disappeared")
}
I've added both forms of init for clarity. Since you are using a storyboard, I'd expect that init(coder:) is the one you need.
Finally, just send the notification when the modal has disappeared:
override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
NotificationCenter.default.post(name: .modalHasDisappeared, object: nil, userInfo: nil)
}
This sends no data, just the fact that the modal has disappeared. If you want to send data - say, a string or a table cell value, change the object parameter to it:
NotificationCenter.default.post(name: .modalHasDisappeared, object: myLabel, userInfo: nil)
And make the following changes in your first VC:
NotificationCenter.default.addObserver(self, selector: #selector(modalHasDisappeared(_:)), name: .modalHasDisappeared, object: nil)
#objc func modalHasDisappeared(_ notification:Notification) {
let label = notification.object as! UILabel!
print(label.text)
}
Last notes:
To repeat, note that by declaring an extension to Notification.Name, I've only have one place where I'm declaring a string.
There is no code in AppDelegate or SceneDelegate, nor any references to `UIApplication(). Try to think of the view (and view controller) as appearing/disappearing, not background/foreground.
While the first view is visually in the background, it's still visible. So the trick is to code against the modal view disappearing instead.

Reloading Table View After Watching a Rewarded Video

Recently I've implemented the rewarded video feature in the code and it works well. Simply, when the user chooses the level from the table view and watches the rewarded video, it unlocks the level. But when the user closes the ad view, table view stays the same, not reloaded with the new information.
I tried some solution I found here but nothing worked.
You probably need to reload the table view manually using tableView.reloadData(). Either do this in viewWillAppear or in any notifications/callbacks that you trigger when the ad has finished playing.
You can set event notification on the reward video opening controller. Use these lines of code in viewDidLoad
GADRewardBasedVideoAd.sharedInstance().delegate = self
GADRewardBasedVideoAdDelegate notifies you of rewarded video lifecycle events. You are required to set the delegate prior to loading an ad. The most important event in this delegate is rewardBasedVideoAd:didRewardUserWithReward:, which is called when the user should be rewarded for watching a video. You may optionally implement other methods in this delegate.
Then you need to implement this delegate
func rewardBasedVideoAd(_ rewardBasedVideoAd: GADRewardBasedVideoAd,
didRewardUserWith reward: GADAdReward) {
print("Reward received with currency: \(reward.type), amount \(reward.amount).")
// RELOAD YOUR TABLE VIEW DATA HERE
}
For details you can see detail implementation here
you can simply do it using NSNotification to call your tableView.reloadData():
add
NotificationCenter.default.addObserver(self, selector: #selector(reload), name: NSNotification.Name(rawValue: "load"), object: nil)
to ur tableView Controller's (TVC) ViewDidLoad
and this function to ur TVC
#objc func reload()
{
//setup ur new data
self.tableView.reloadData()
}
then just add
NotificationCenter.default.post(name: NSNotification.Name(rawValue: "load"), object: nil)
befor ur self.dismiss(animated: true, completion: nil) in ur RewardedVideo Player

how to use protocol and delegate methods for viewcontroller that are not directly connected?

Im new to swift and iOS development.I have a doubt regarding protocol and delegate methods.
I have a 4 vc's say vc1,vc2,vc3,vc4.And i'm navigating from vc1->vc2->vc3-vc4->vc1. That is from vc4, im poping using navigation controller back to vc1.
i have a protocol and methods in it like
protocol myProtocol{
func myFunc()
}
In vc4, im making a delegate as,
var delegate:myProtocol?
and im using it in a button action as
if let delegate = self.delegate{
delegate.myFunc()
}
and also pop vc4 back to vc1.
Now in VC1,im extending myProtocol as
class vc1:myProtocol{
override func viewDidLoad()
{
let vcProtocol = vc4()
vc4.delegate = self
}
func myFunc()
{
print("executing this")
}
}
But its not working. Can i do like this?
How can i connect these to classes with delegate and protocol.Please help me
viewDidLoad is only executed once if the controller is not destroyed.
Try calling in viewWillAppear for example.
Also, you do not need to change the delegate of vc4, just set the delegate to vc1 again (in viewWillAppear).
Have you tried Notification?
In your VC1 ViewController ViewDidLoad method:
NotificationCenter.default.addObserver(self, selector: #selector(myFunc, name: NSNotification.Name(rawValue: "aNotificationName"), object: nil)
In your VC4 when the myFunc is needed:
NotificationCenter.default.post(name: Notification.Name("aNotificationName"), object: nil)
You can get the viewController from the navigation stack which has the same type as your first viewController and then assign it as the delegate object in your vc4.
For instance:
In vc4's viewDidLoad, you may do this
for viewController in self.navigationController?.viewControllers{
if viewController.isKindOfClass(YourVC1ControllerType){
self.delegate = viewController
}
}
I assume that your vc1,vc2,vc3, etc have their own ViewController custom classes.
Another way of implementing this would be to get the first controller from the self.navigationController?.viewControllers array and setting it as the delegate object in vc4.
//In viewDidLoad of vc4
delegate = self.navigationController?.viewControllers.first as! HomeController
or,
//In viewDidLoad of vc4
delegate = self.navigationController?.viewControllers.[indexOfTheController] as! HomeController

After seguing from ViewController 1 to ViewController 2 is there a way to let VC2 know that VC1 has completed loading async data (swift)?

There is this post re: passing data between view controllers:
Passing Data between View Controllers
I don't think what i'm after is on there.
In ViewController 1 I load async data from firebase and i'd like to go to ViewController 2 without waiting for VC 1 to return all the data.
On VC2 there is a button that I want disabled until VC 1 has finished.
I did try setting a property in my singleton to true when the data has finished loading and then in VC2 looping until this property returned true but it appears once I have segued from VC1 then it won't set the property in my singleton to true in the background.
Thx.
Of course there are many solutions, you might try to use the NotificationCenter, doing something like:
// in VC2: let's start listening for VC1 callback
NotificationCenter.default.addObserver(self, selector: #selector(self.callbackFromVC1(_:)), name: Notification.Name("VC1HasFinished"), object: nil)
// in VC2: this is the callback will be executed
func callbackFromVC1(_ notification: NSNotification? = nil) {
let userInfoFromVC1:[AnyHashable : Any]? = notification?.userInfo
// do something with userInfoFromVC1
}
....
// in VC1: when your async stuff is finished, push "userInfoFromVC1" into the notification...
NotificationCenter.default.post(name: NSNotification.Name.init(rawValue: "VC1HasFinished"), object: nil, userInfo:userInfoFromVC1)

NSNotification addObserver in two ViewControllers Swift

In my HomeViewController viewDidLoad method I have an observer that looks out for a new notification. When observed it segues to a SecondTableVC. I have an observer in the second VC looking for the same notification, but the second observer isn't seeing the notification and calling the method. Thanks in advance to anyone who can explain what I'm missing here? I removed the observer in both viewDidLoad and in the segue method, but it doesn't fix it.
var childVC: UIViewController!
override func viewDidLoad() {
super.viewDidLoad()
childVC = self.storyboard?.instantiateViewControllerWithIdentifier("WordListsTableViewController")
// check for new notification - if there is segue to the SecondTableVC
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(HomeViewController.showChildVC), name: "NotificationActionPressed", object: nil) // Segue works fine.
}
func showChildVC() {
self.view.addSubview(childVC.view)
}
In SecondTableVC
override func viewDidLoad() {
super.viewDidLoad()
// check for new notification - if there is
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(SecondTableVC.newNotif), name: "NotificationActionPressed", object: nil)
}
func newNotif() {
print("new notif") // THIS METHOD IS NOT GETTING CALLED
}
Kind of piggybacking off of the answer from Phillip: If it is absolutely necessary that the second view controller listen to the NSNotification event, then the second view controller can be instantiated from the storyboard and held in memory by the first view controller until it needs to be displayed. In this case, the second view controller should subscribe to the notification event upon initialization.
Your segue causes the second view controller to be created. If the segue is triggered by a notification, then the SecondTableVC's viewDidLoad hasn't happened when the notification fires.
The second controller's not receiving the notification because it not only hasn't registered by that time, but doesn't actually exist.