2

So I have built my single view application in swift and Xcode. All my code is in one file, the main ViewController.swift to make things easier as the codes get bigger I have started to move the methods to a separate swift file to keep things organise - ClipManager.swift.

I have 3 methods which all use the notifyUser method which calls UIAlertController.

So I have moved this method to the same file, ClipManager.swift but now my Alerts are not showing when these methods are called in the current ViewController - ViewController.swiftas the methods are in a separate file.

Firstly my Method that uses UIAlert

////Located in ClipManager.swift
class ClipManager: UIViewController {
func notifyUser(title: String, message: String) -> Void
    {
        let alert = UIAlertController(title: title,
            message: message,
            preferredStyle: UIAlertControllerStyle.Alert)

        let cancelAction = UIAlertAction(title: "OK",
            style: .Cancel, handler: nil)

        alert.addAction(cancelAction)
        self.presentViewController(alert, animated: true,
            completion: nil)
    }}

The call of my Method from ViewController.swift

class ViewController: UIViewController {
///// In ViewController.swift (where I want the Alert to show)
let SavedRecord = MyClipManager.SaveMethod(publicDatabase!, myRecord: record)

}

The code for SaveMethod located in ClipManager.swift

 func SaveMethod(publicDatabase: CKDatabase, myRecord:CKRecord ) -> CKRecord {

        publicDatabase.saveRecord(myRecord, completionHandler:
            ({returnRecord, error in
                if let err = error {

                    //// **** Notify called here *****
                    self.notifyUser("Save Error", message:
                        err.localizedDescription)
                } else {
                    dispatch_async(dispatch_get_main_queue()) {
                        self.notifyUser("Success",
                            message: "Record saved successfully")
                    }


                }
            }))
     return myRecord
    }

I'm guessing my Alerts are not showing because they are actually being triggered on ClipManager.swift which isn't in view.

What are my options here, Move NotifyUser back to ViewController.swift and create and object of this in ClipManager.swift to call it in my methods located there?

Or is there a way to pass these Alerts to the shown view?

Malorrr
  • 263
  • 4
  • 13

3 Answers3

3

hi here how i will do in your place.

For my ClipManager class it will extends from NSObject. no need from UIView controller

here how the class should look like

class ClipManager: NSObject {
func notifyUser(title: String, message: String) -> Void
{
    let alert = UIAlertController(title: title,
        message: message,
        preferredStyle: UIAlertControllerStyle.Alert)

    let cancelAction = UIAlertAction(title: "OK",
        style: .Cancel, handler: nil)

    alert.addAction(cancelAction)
    UIApplication.sharedApplication().keyWindow?.rootViewController!.presentViewController(alert, animated: true,
        completion: nil)
}
}

for presenting the alertView i use the rootViewController of the application

No change to make in your ViewController class.

let me know if it works for you :)

  • Thank you so much! this has worked perfectly... Could you explain to me how this has changed, I understand that rootviewcontroller is picking the first view controller? Why is it changed to NSObject? – Malorrr Jan 21 '16 at 22:33
  • for the NSObject it just to tell you that you could use a simple swift class for the notify management. the rootView controller is the Root View Contains Your Content – BEN MESSAOUD Mahmoud Jan 21 '16 at 22:35
  • The `NSObject` part is irrelevant to the solution, everything in Swift inherits from `NSObject` and there's no difference between explicitly inheriting it here in your class file and not including it. – pbush25 Jan 21 '16 at 23:27
  • yes i know. i did this just to show that have modified the ClipManager super class. thanks @pbush25 for your precession :) – BEN MESSAOUD Mahmoud Jan 22 '16 at 06:15
2

I used BEN MESSAOUD Mahmoud way of doing things, but ran in to a small error at time with: "Attempt to present on whose view is not in the window hierarchy!"

I wound up changing it a bit to solve this. I pass the view controller along with the call to notifyUser. Then it will present from whatever VC I am in.

func notifyUser(title: String, message: String, fromController: UIViewController) -> Void{
let alert = UIAlertController(title: title,
    message: message,
    preferredStyle: UIAlertControllerStyle.Alert)

let cancelAction = UIAlertAction(title: "OK",
    style: .Cancel, handler: nil)

alert.addAction(cancelAction)
fromController.presentViewController(alert, animated: true,
    completion: nil)
}

then I would just call it:

Clipmanager.notifyUser("title", message: "message", fromController: self)

Got some help with this from Sulthan on this link AlertController is not in the window hierarchy

Community
  • 1
  • 1
Stan
  • 31
  • 5
1

Update of Stan and BEN MESSAOUD's answers for Swift 3:

class ClipManager: NSObject {

func notifyUser(title: String, message: String, fromController: UIViewController) -> Void
{
    let alert = UIAlertController(title: title,
                                  message: message,
                                  preferredStyle: UIAlertControllerStyle.alert)

    let cancelAction = UIAlertAction(title: "OK",
                                     style: .cancel, handler: nil)

    alert.addAction(cancelAction)
    fromController.present(alert, animated: true, completion: nil)
}}

And to call it:

let clipMGR = ClipManager()

clipMGR.notifyUser(title: "Title", message: "Message", fromController: self)
agrippa
  • 819
  • 10
  • 8