简体   繁体   中英

Use internal func from a class to another class in swift

I have a profile class and settings class

profile class contains an internal function

class Profile: UIViewController,UIImagePickerControllerDelegate,UINavigationControllerDelegate {

   internal func profileSelectFromGallery(sender: Profile){
        let myPickerController = UIImagePickerController()
        myPickerController.delegate = sender;
        myPickerController.sourceType =
            UIImagePickerControllerSourceType.PhotoLibrary
        sender.presentViewController(myPickerController, animated:true, completion: nil)
    }
}

I want to use profileSelectFromGallery in setting class and I have two tries below

class SettingsVC: UITableViewController {
   // I will call this private function on a click events
   private func selectFromGallery(){

            // let profile = Profile()
            // profile.profileSelectFromGallery(self)
            Profile.profileSelectFromGallery(self)

   }
}

The above codes results into Cannot convert value of type 'SettingsVC' to expected argument type 'Profile' since profileSelectFromGallery needs a parameter of a class Profile so what i want to do is change sender so that i can use it from any of my class and not just my Profile class .

So the problem is that you can't convert a SettingsVC into a Profile . If you look at the method signature you'll see it's expecting a Profile :

internal func profileSelectFromGallery(sender: Profile)

You are trying to pass in a SettingVC in selectFromGallery()

Inside profileSelectFromGallery you want the sender to be both a UIViewController and a UIImagePickerControllerDelegate . There's a couple ways you could do this:

The simplest is to change the method signature. You'd do something like this:

   internal func profileSelectFromGallery(sender: UIImagePickerControllerDelegate){
        guard let vc = sender as? UIViewController else {
           return
        }

        let myPickerController = UIImagePickerController()
        myPickerController.delegate = sender;
        myPickerController.sourceType =
            UIImagePickerControllerSourceType.PhotoLibrary
        vc.presentViewController(myPickerController, animated:true, completion: nil)
    }

Theres 2 main things here: sender is changed to the proper delegate method, and theres a guard statement to cast it to a VC for the presentViewController call.

The much more awesome way to do this is to use protocol extensions!

extension UIImagePickerControllerDelegate where Self: UIViewController, Self: UINavigationControllerDelegate {
    func profileSelectFromGallery() {
        let myPickerController = UIImagePickerController()
        myPickerController.delegate = self
        myPickerController.sourceType = UIImagePickerControllerSourceType.PhotoLibrary
        self.presentViewController(myPickerController, animated:true, completion: nil)
    }
}

Basically what I'm doing here is adding a method for every UIImagePickerControllerDelegate thats also an UIViewController and an UINAvigationControllerDelegate . This means that I can call it on both Profile and SettingVC (once you add the necessary delegates to SettingVC). All you would need to do is:

let profile = Profile()
profile.profileSelectFromGallery()

let settingVC = SettingVC()
settingVC.profileSelectFromGallery()

Declare new protocol as:

protocol PickerProtocol : UIImagePickerControllerDelegate, UINavigationControllerDelegate {

}

Now your Profile class will look like:

class Profile: UIViewController, PickerProtocol {

//Option 1
internal func profileSelectFromGallery(contoller: UIViewController, pickerProtocol: PickerProtocol){

    let myPickerController = UIImagePickerController()

    myPickerController.delegate = pickerProtocol

    myPickerController.sourceType =
        UIImagePickerControllerSourceType.PhotoLibrary
    contoller.presentViewController(myPickerController, animated:true, completion: nil)
}

//Option 2
internal func profileSelectFromGalleryOption2(sender : UIViewController? ) {

    var viewContoller : UIViewController = self
    if let unwrappedSender = sender {
        viewContoller = unwrappedSender
    }

    let myPickerController = UIImagePickerController()

    if let pickerProtocol = viewContoller as? PickerProtocol {
        myPickerController.delegate = pickerProtocol
    } else {
        myPickerController.delegate = self //Assign self as default
    }

    myPickerController.sourceType = UIImagePickerControllerSourceType.PhotoLibrary
    viewContoller.presentViewController(myPickerController, animated:true, completion: nil)
}

}

class SettingsVC1: UITableViewController {
    // I will call this private function on a click events
    private func selectFromGallery(){

        let profile = Profile()
        profile.profileSelectFromGallery(self, pickerProtocol:profile)
        profile.profileSelectFromGalleryOption2(self)
        //Or
        profile.profileSelectFromGalleryOption2(nil)//profile itself delegate and presenting controller
    }
}

// OR

class SettingsVC2: UITableViewController, PickerProtocol {
    // I will call this private function on a click events
    private func selectFromGallery(){

        let profile = Profile()
        profile.profileSelectFromGallery(self, pickerProtocol:self)
        profile.profileSelectFromGalleryOption2(self)
        //Or
        profile.profileSelectFromGalleryOption2(nil)//profile itself delegate and presenting controller
    }
}

I would use POP (protocol oriented programming) like this:

protocol SelectorProtocol: UIImagePickerControllerDelegate, UINavigationControllerDelegate {
}

extension SelectorProtocol where Self: UIViewController {
    func profileSelectFromGallery() {
        let myPickerController = UIImagePickerController()
        myPickerController.delegate = self;
        myPickerController.sourceType = UIImagePickerControllerSourceType.PhotoLibrary
        self.presentViewController(myPickerController, animated:true, completion: nil)
    }
}

class Profile: UIViewController,UIImagePickerControllerDelegate,UINavigationControllerDelegate, SelectorProtocol {
    func foo() {
        profileSelectFromGallery()
    }
}

class SettingsVC: UITableViewController, SelectorProtocol {
    // I will call this private function on a click events
    private func selectFromGallery(){
        profileSelectFromGallery()
    }
}

You are trying to statically call profileSelectFromGallery: even though it is an instance method.

Try changing the method definition to:

internal static func profileSelectFromGallery(sender: Profile){

As for being able to use any class as a delegate, create a custom Protocol and ensure that the sender conforms to this protocol. See here (specifically the heading titled Protocols ) for more information: http://www.raywenderlich.com/115300/swift-2-tutorial-part-3-tuples-protocols-delegates-and-table-views

perhaps the following will work:

   class SettingsVC: UITableViewController {
   // I will call this private function on a click events
   private func selectFromGallery(){
       let prof = Profile()
       prof.profileSelectFromGallery(prof)
   }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM