I am using Swift 4 and I am wondering how having a reference to a ViewController in AppDelegate works. I have two questions which I have put in bold. I understand that AppDelegate is a delegate that has functions that get called when the app becomes foreground or background, or even when the user does the "open with" event on a file extension that my app is registered to handle and selects to open that file with my app- AppDelegate lets the app know that took place. 1) But what I don't understand is how AppDelegate should communicate with my Views to tell them that these events happened. I am wondering what the good design pattern is for doing so. My solution is to have a reference to a viewController so here is an example:
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
var hotSpotRISViewController = HotSpotRISViewController()
...
func application(_ app: UIApplication, open url: URL,
options: [UIApplicationOpenURLOptionsKey : Any]) -> Bool {
hotSpotRISViewController.setURL(theURL: url)
return true
}
}
What I don't understand is how this actually works. I thought that AppDelegate looks at Main.storyboard and starts that and that Main.storyboard has it's own reference to HotSpotRISViewController(). 2) How is it that by making a reference to HotSpotRISViewController() in the AppDelegate, that it uses this reference instead?
Related
I use Kugel Library for Notification (https://github.com/TakeScoop/Kugel/tree/swift-3.0). I want to know how to remove Observer and where in my code . i use Unsubscribe for library and nothing happens
override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
Kugel.unsubscribe("SleepMode")
Kugel.unsubscribe("SleepModeSynchroMode")
Kugel.unsubscribe(self, name: NSNotification.Name(rawValue: "SleepMode"), object: nil)
Kugel.unsubscribe(self, name: NSNotification.Name(rawValue: "SleepModeSynchroMode"), object: nil)
NotificationCenter.default.removeObserver(self, name: Notification.Name(rawValue: "SleepMode"), object: nil);
NotificationCenter.default.removeObserver(self, name: Notification.Name(rawValue: "SleepModeSynchroMode"), object: nil);
}
i want remove subscribe notification ( add observer ) when i go back to other view.
I use denit { } but the notification that doesn't killed .
Can you helpme
Tahnks
All that is wrong. Here is the right way to remove observers in Swift (also applies to Obj-C):
According to Apple's documentation, you have to keep a reference to your observer! NSNotificationCenter addObserver Self is not an observer so NotificationCenter.default.removeObserver(self, name: Notification.Name(rawValue: "SleepMode"), object: nil); doesn't do anything.
What you have to do is:
Extend the Notification.Name for your notification: (where you post the notification)
extension Notification.Name {
static let notification = Notification.Name(rawValue: "A notification")
}
Create a weak reference to your observer with:
weak var observer: NSObjectProtocol?
Create an "addObserver" function like so: (where you want to listen to the notification)
func addObserver() {
guard observer == nil else { return }
observer = NotificationCenter.default.addObserver(forName: .notification,
object: nil,
queue: .main) { notification in
print("Notification triggered")
}
Create a "removeObserver" function:
func removeObserver() {
guard let observer = observer else { return }
NotificationCenter.default.removeObserver(observer)
}
Call your "addObserver" function from wherever you need it in your code (most probably from your viewDidLoad method)
Call the "removeObserver" function when you are done listening to that notification.
An important point here is that if you have an extra strong reference to your class implementing the notification and you "think" the observer is removed but it is not, then the guard implementation above prevents your code from creating several observers. This is particularly the case for some implementations of addObserver in the viewDidLoad function missing a removeObserver.
A proof? add a breakpoint in the addObserver function at the line where you assign the observer and edit the breakpoint (right click) then choose add action and pick Sound and select the option Automatically continue after evaluating actions.
Start your app and go back and forth in the view that implements the observer. If the number of time you hear the sound is constant, you're done! Otherwise you should here the sound increase by one each time you enter the view. There you go!
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 deallocation method. If your app targets earlier releases, you need to keep a reference to the observer object and submit it instead of 'self', also the library says its been Deprecated why are you using it?
Try and remove the observer in viewWillAppear
Whats the best way to pass data to a UITabBarController from a UIViewController in Swift 3?
I am building a single view application and I have a details view which needs to be split into 4 sections. I want to use a TabBar to achieve this and pass an ID from a list in UIViewController and then pass that value down to each individual UIViewController in the TabBar. This is so that I can call a web method which takes the ID to fill out data in the individual views.
The app is being converted from Obj-C with a Storyboard to Swift 3 without a Storyboard so I don't have access to the usual segue definitions I did have. I also used to use UserDefaults in the Obj-C version to save away the selected ID and then pull it out again in the individual views. However, I'm not convinced this is the best way to achieve what I am after.
So far I have tried passing along by accessing the UITabBarController class in the initial UIViewController and setting a variable in the ViewController and then passing it down to the ViewController in the first tab. This works if I am pushing from UIViewController to UIViewController (The first view in the TabBar, but run standalone) but doesn't work when the target Controller is a TabBarController.
I have also tried posting a Notification in the ViewControler and Observing the result in the TabBarController. However the observe code is never called. I'm using:
Selected Row:
NotificationCenter.default.post(name: notificationName, object: selectedRowID)
Then in ViewDidLoad on the TabBarController (Also tried viewDidAppear and viewWillAppear):
NotificationCenter.default.addObserver(self, selector: #selector(setID), name: notificationName, object: nil)
The above works, BUT, only when I select the second tab and then go back to the first tab and then it gets called twice!?!?!
I have also tried a Singleton class, but that just flat out didn't work.
Is using UserDefaults really the best way to do this?
You can create a new class holding the variables to pass the value:
class MyTabController: UITabBarController {
var myPassedString = String()
}
Go to the StoryBoard, select the tab bar controller and open the Identity inspector, change the class to: MyTabController.
let tabBarController = window?.rootViewController as? UITabBarController
Define in each ViewController where you need the shared data:
var myPassedString = String()
To make to this variable shared, code in each ViewController:
override func viewDidLoad() {
super.viewDidLoad()
myPassedString = (tabBarController as! MyTabController).myPassedString
}
Thanks. I am not using a storyboard.
Got it working using a singleton after realising that
1. To get the values back out you must call the singleton in viewWillAppear rather than viewDidLoad and
2. When programmatically creating this, the viewWillAppear of the first child view in the TabBar is observed instead of the viewWillAppear of the actual TabBar controller itself.
for reference for anyone else trying to do similar, my code as follows
open class LastAccessedEvent {
var ID : String = ""
class var sharedInstance : LastAccessedEvent {
struct Static {
static let instance : LastAccessedEvent = LastAccessedEvent()
}
return Static.instance
}
var EventID : String {
get{
return self.ID
}
set {
self.ID = newValue
}
}
}
then in the viewWillAppear of the child view,
if !LastAccessedEvent.sharedInstance.ID.isEmpty{
let myEventID = LastAccessedEvent.sharedInstance.ID
}
I have created a time activate on the View Controller.
It needs to call a selector, and for that selector, I am calling a function.
When the function is in the View Controller file, it works. If i put this function in another Swift file that I created in the app, it does not find the Selector and I get an error during runtime.
Is it possible to put functions in Swift in different files or not?
#IBAction func startNotificationTimer(sender: AnyObject) {
timer = NSTimer.scheduledTimerWithTimeInterval(10, target: self, selector: "update_start", userInfo: nil, repeats: true)
timerStatus.text = "Started"
}
"update_start" is in a different file.
Thanks for the help
It doesn't matter what file your update_start method is in, but it does matter that it be a method in your View Controller class. If you define it in a file other than the one where that class is declared, you'll need to define the method in an extension on that class.
Also, NSTimer selectors should end with a colon (update_start:), because they take a single parameter (the timer) when called.
I am creating my first app with storyboards. So far, I have two ViewControllers - on the first VC, the user taps a button, and it takes them to the second VC, using a 'Present modally" segue.
Is there some method that is called when the new view appears? I want to be able to write the code to start the game in here.
You should look at viewDidLoad(), viewWillAppear(_:) and viewDidAppear(_:). Most likely what you need is the first one.
I think you're searching for the prepareForSegue method:
override func prepareForSegue(segue: UIStoryboardSegue!, sender: AnyObject!) {
if (segue.identifier == "Load View") {
// pass data to next view
}
}
It's called right before the segue is performed so you can for example identify the target ViewController and pass it some params.
I start project in Swift Language. Apps almost done. Single ViewController logics are all done. But I need to communicate with each other ViewController.
I want to pass some value from one ViewController to another ViewController. I'm using StoryBoard. I want to pass value using prepareSeague function as like Objective-C has. Is there any way to do this without using delegate-way.
In the first view controller handle prepareForSegue method and provide additional values to the second view controller, like:
override func prepareForSegue(segue: UIStoryboardSegue!, sender: AnyObject!) {
if segue.identifier == "someidentifier" {
let vc = segue.destinationViewController as MySecondViewController
// vc.someProperty = someValue
}
}