Delegates in swift?

2018-12-31 08:09发布

How does one go about making a delegate, i.e. NSUserNotificationCenterDelegate in swift?

12条回答
深知你不懂我心
2楼-- · 2018-12-31 08:47

Delegates always confused me until I realized that a delegate is just a class that does some work for another class. It's like having someone else there to do all the dirty work for you that you don't want to do yourself.

I wrote a little story to illustrate this. Read it in a Playground if you like.

Once upon a time...

// MARK: Background to the story

// A protocol is like a list of rules that need to be followed.
protocol OlderSiblingDelegate: class {
    // The following command (ie, method) must be obeyed by any 
    // underling (ie, delegate) of the older sibling.
    func getYourNiceOlderSiblingAGlassOfWater()
}

// MARK: Characters in the story

class BossyBigBrother {

    // I can make whichever little sibling is around at 
    // the time be my delegate (ie, slave)
    weak var delegate: OlderSiblingDelegate?

    func tellSomebodyToGetMeSomeWater() {
        // The delegate is optional because even though 
        // I'm thirsty, there might not be anyone nearby 
        // that I can boss around.
        delegate?.getYourNiceOlderSiblingAGlassOfWater()
    }
}

// Poor little sisters have to follow (or at least acknowledge) 
// their older sibling's rules (ie, protocol)
class PoorLittleSister: OlderSiblingDelegate {

    func getYourNiceOlderSiblingAGlassOfWater() {
        // Little sis follows the letter of the law (ie, protocol),
        // but no one said exactly how she had to respond.
        print("Go get it yourself!")
    }
}

// MARK: The Story

// Big bro is laying on the couch watching basketball on TV.
let bigBro = BossyBigBrother()

// He has a little sister named Sally.
let sally = PoorLittleSister()

// Sally walks into the room. How convenient! Now big bro 
// has someone there to boss around.
bigBro.delegate = sally

// So he tells her to get him some water.
bigBro.tellSomebodyToGetMeSomeWater()

// Unfortunately no one lived happily ever after...

// The end.

In review, there are three key parts to making and using the delegate pattern.

  1. the protocol that defines what the worker needs to do
  2. the boss class that has a delegate variable, which it uses to tell the worker class what to do
  3. the worker class that adopts the protocol and does what is required

Real life

In comparison to our Bossy Big Brother story above, delegates are often used for the following practical applications:

  1. Communication: one class needs to send some information to another class.
  2. Customization: one class wants to allow another class to customize it.

The great part is that these classes don't need to know anything about each other beforehand except that the delegate class conforms to the required protocol.

I highly recommend reading the following two articles. They helped me understand delegates even better than the documentation did.

One more note

Delegates that reference other classes that they do not own should use the weak keyword to avoid strong reference cycles. See this answer for more details.

查看更多
路过你的时光
3楼-- · 2018-12-31 08:48

In swift 4.0

Create a delegate on class that need to send some data or provide some functionality to other classes

Like

protocol GetGameStatus {
    var score: score { get }
    func getPlayerDetails()
}

After that in the class that going to confirm to this delegate

class SnakesAndLadders: GetGameStatus {
    func getPlayerDetails() {

 }
}
查看更多
旧时光的记忆
4楼-- · 2018-12-31 08:50

Here's a gist I put together. I was wondering the same and this helped improve my understanding. Open this up in an Xcode Playground to see what's going on.

protocol YelpRequestDelegate {
    func getYelpData() -> AnyObject
    func processYelpData(data: NSData) -> NSData
}

class YelpAPI {
    var delegate: YelpRequestDelegate?

    func getData() {
        println("data being retrieved...")
        let data: AnyObject? = delegate?.getYelpData()
    }

    func processYelpData(data: NSData) {
        println("data being processed...")
        let data = delegate?.processYelpData(data)
    }
}

class Controller: YelpRequestDelegate {
    init() {
        var yelpAPI = YelpAPI()
        yelpAPI.delegate = self
        yelpAPI.getData()
    }
    func getYelpData() -> AnyObject {
        println("getYelpData called")
        return NSData()
    }
    func processYelpData(data: NSData) -> NSData {
        println("processYelpData called")
        return NSData()
    }
}

var controller = Controller()
查看更多
美炸的是我
5楼-- · 2018-12-31 08:52

DELEGATES IN SWIFT 2

I am explaining with example of Delegate with two viewControllers.In this case, SecondVC Object is sending data back to first View Controller.

Class with Protocol Declaration

protocol  getDataDelegate  {
    func getDataFromAnotherVC(temp: String)
}


import UIKit
class SecondVC: UIViewController {

    var delegateCustom : getDataDelegate?
    override func viewDidLoad() {
        super.viewDidLoad()
     }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
    @IBAction func backToMainVC(sender: AnyObject) {
      //calling method defined in first View Controller with Object  
      self.delegateCustom?.getDataFromAnotherVC("I am sending data from second controller to first view controller.Its my first delegate example. I am done with custom delegates.")
        self.navigationController?.popViewControllerAnimated(true)
    }

}

In First ViewController Protocol conforming is done here:

class ViewController: UIViewController, getDataDelegate

Protocol method definition in First View Controller(ViewController)

func getDataFromAnotherVC(temp : String)
{
  // dataString from SecondVC
   lblForData.text = dataString
}

During push the SecondVC from First View Controller (ViewController)

let objectPush = SecondVC()
objectPush.delegateCustom = self
self.navigationController.pushViewController(objectPush, animated: true)
查看更多
与风俱净
6楼-- · 2018-12-31 08:55

The solutions above seemed a little coupled and at the same time avoid reuse the same protocol in other controllers, that's why I've come with the solution that is more strong typed using generic type-erasure.

@noreturn public func notImplemented(){
    fatalError("not implemented yet")
}


public protocol DataChangedProtocol: class{
    typealias DataType

    func onChange(t:DataType)
}

class AbstractDataChangedWrapper<DataType> : DataChangedProtocol{

    func onChange(t: DataType) {
        notImplemented()
    }
}


class AnyDataChangedWrapper<T: DataChangedProtocol> : AbstractDataChangedWrapper<T.DataType>{

    var base: T

    init(_ base: T ){
        self.base = base
    }

    override func onChange(t: T.DataType) {
        base.onChange(t)
    }
}


class AnyDataChangedProtocol<DataType> : DataChangedProtocol{

    var base: AbstractDataChangedWrapper<DataType>

    init<S: DataChangedProtocol where S.DataType == DataType>(_ s: S){
        self.base = AnyDataChangedWrapper(s)
    }

    func onChange(t: DataType) {
        base.onChange(t)
    }
}



class Source : DataChangedProtocol {
    func onChange(data: String) {
        print( "got new value \(data)" )
    }
}


class Target {
    var delegate: AnyDataChangedProtocol<String>?

    func reportChange(data:String ){
        delegate?.onChange(data)
    }
}


var source = Source()
var target = Target()

target.delegate = AnyDataChangedProtocol(source)
target.reportChange("newValue")    

output: got new value newValue

查看更多
无色无味的生活
7楼-- · 2018-12-31 08:57

I got few corrections to post of @MakeAppPie

First at all when you are creating delegate protocol it should conform to Class protocol. Like in example below.

protocol ProtocolDelegate: class {
    func myMethod(controller:ViewController, text:String)
}

Second, your delegate should be weak to avoid retain cycle.

class ViewController: UIViewController {
    weak var delegate: ProtocolDelegate?
}

Last, you're safe because your protocol is an optional value. That means its "nil" message will be not send to this property. It's similar to conditional statement with respondToselector in objC but here you have everything in one line:

if ([self.delegate respondsToSelector:@selector(myMethod:text:)]) {
    [self.delegate myMethod:self text:@"you Text"];
}

Above you have an obj-C example and below you have Swift example of how it looks.

delegate?.myMethod(self, text:"your Text")
查看更多
登录 后发表回答