Delegaci w swift?

Jak zrobić delegata, czyli NSUserNotificationCenterDelegate W swift?

Author: Benjamin, 2014-06-07

12 answers

Nie różni się tak bardzo od obj-c. Najpierw musisz określić protokół w deklaracji klasy, jak poniżej:

class MyClass: NSUserNotificationCenterDelegate

Implementacja będzie wyglądać następująco:

// NSUserNotificationCenterDelegate implementation
func userNotificationCenter(center: NSUserNotificationCenter, didDeliverNotification notification: NSUserNotification) {
    //implementation
}

func userNotificationCenter(center: NSUserNotificationCenter, didActivateNotification notification: NSUserNotification) {
    //implementation
}

func userNotificationCenter(center: NSUserNotificationCenter, shouldPresentNotification notification: NSUserNotification) -> Bool {
    //implementation
    return true
}

Oczywiście, musisz ustawić delegata. Na przykład:

NSUserNotificationCenter.defaultUserNotificationCenter().delegate = self;
 69
Author: Adam,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-03-15 04:33:28

Oto mała pomoc na temat delegatów pomiędzy dwoma kontrolerami widoku:

Krok 1: Utwórz protokół w UIViewController, który będzie usuwany/będzie wysyłał dane.

protocol FooTwoViewControllerDelegate:class {
    func myVCDidFinish(_ controller: FooTwoViewController, text: String)
}

Krok 2: Zadeklaruj delegata w klasie wysyłającej (np. UIViewcontroller)

class FooTwoViewController: UIViewController {
    weak var delegate: FooTwoViewControllerDelegate?
    [snip...]
}

Krok 3: Użyj delegata w metodzie klasowej, aby wysłać dane do metody odbierającej, która jest dowolną metodą, która przyjmuje protokół.

@IBAction func saveColor(_ sender: UIBarButtonItem) {
        delegate?.myVCDidFinish(self, text: colorLabel.text) //assuming the delegate is assigned otherwise error
}

Krok 4: Przyjmuje protokół w klasie przyjmującej

class ViewController: UIViewController, FooTwoViewControllerDelegate {

Krok 5: zaimplementuj metodę delegata

func myVCDidFinish(_ controller: FooTwoViewController, text: String) {
    colorLabel.text = "The Color is " +  text
    controller.navigationController.popViewController(animated: true)
}

Krok 6: Ustaw delegata w preparedforsegue:

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    if segue.identifier == "mySegue" {
        let vc = segue.destination as! FooTwoViewController
        vc.colorString = colorLabel.text
        vc.delegate = self
    }
}
I to powinno zadziałać. To oczywiście tylko fragmenty kodu, ale powinno dać ci pomysł. Aby uzyskać długie wyjaśnienie tego kodu, możesz przejść do mojego wpisu na blogu tutaj:

Segmenty i delegaci

Jeśli jesteś zainteresowany tym, co dzieje się pod maską z delegat napisałem o tym tutaj:

Pod maską z delegatami

 207
Author: MakeAppPie,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-02-05 11:24:47

Delegaci zawsze mnie mylili, dopóki nie zdałem sobie sprawy, że delegat to tylko klasa, która wykonuje jakąś pracę dla innej klasy {4]}. To tak, jakby ktoś inny odwalił za Ciebie brudną robotę, której sam nie chcesz robić.

Napisałem małą historię, aby to zilustrować. Przeczytaj to na Placu Zabaw, jeśli chcesz.

Dawno, dawno temu...
// 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.

W przeglądzie, istnieją trzy kluczowe części tworzenia i używania wzorca delegata.

  1. the Protokół , który określa, co pracownik musi zrobić
  2. Klasa boss , która ma zmienną delegata, której używa, aby powiedzieć klasie worker, co ma robić
  3. klasa robotnicza , która przyjmuje protokół i robi to, co jest wymagane

Prawdziwe życie

W porównaniu do naszej apodyktycznej historii Big Brothera powyżej, delegaci są często używani do następujących praktycznych zastosowań:

  1. Komunikacja : jedna klasa musi wysłać jakieś informacje do innej klasy.
  2. dostosowywanie : jedna klasa chce, aby inna klasa mogła ją dostosować.

Najlepsze jest to, że te klasy nie muszą wiedzieć nic o sobie wcześniej, z wyjątkiem tego, że Klasa delegata jest zgodna z wymagany protokół.

[[2]}Gorąco polecam przeczytanie następujących dwóch artykułów. Pomogły mi zrozumieć delegatów jeszcze lepiej niż dokumentacja .

Jeszcze jedna uwaga

Delegaci, którzy odwołują się do innych klas, których nie posiadają, powinni użyć słowa kluczowego weak, aby uniknąć silnego odniesienia cykle. Zobacz ta odpowiedź aby uzyskać więcej szczegółów.

 84
Author: Suragch,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:34:40

Dostałem kilka poprawek do posta @MakeAppPie

Po pierwsze, kiedy tworzysz protokół delegata, powinien on być zgodny z protokołem klasy. Jak w przykładzie poniżej.

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

Po drugie, twój delegat powinien być słaby, aby uniknąć cyklu zatrzymania.

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

Na koniec, jesteś bezpieczny, ponieważ twój protokół jest wartością opcjonalną. Oznacza to, że wiadomość "nil" nie zostanie wysłana do tej właściwości. Jest to podobne do instrukcji warunkowej z respondToselector w objC, ale tutaj masz wszystko w jednej linii:

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

Powyżej masz przykład obj-C, a poniżej masz szybki przykład, jak to wygląda.

delegate?.myMethod(self, text:"your Text")
 45
Author: Shial,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-12-02 15:22:27

Oto gist ułożyłem razem. Zastanawiałam się nad tym samym i to pomogło mi lepiej zrozumieć. Otwórz to w Xcode Playground , aby zobaczyć, co się dzieje.

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()
 30
Author: SeeMeCode,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-12-02 15:25:00

DELEGACI W SWIFT 2

Wyjaśniam przykładem delegata z dwoma viewControllers.In w tym przypadku obiekt SecondVC odsyła dane z powrotem do kontrolera pierwszego widoku.

Klasa z deklaracją protokołu

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)
    }

}

W pierwszej konfiguracji protokołu ViewController odbywa się tutaj:

class ViewController: UIViewController, getDataDelegate

Definicja metody Protokołu w kontrolerze pierwszego widoku (ViewController)

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

Podczas wypychania drugiego kontrolera widoku (ViewController)

let objectPush = SecondVC()
objectPush.delegateCustom = self
self.navigationController.pushViewController(objectPush, animated: true)
 8
Author: Maninderjit Singh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-05-13 07:14:53

Pierwsza klasa:

protocol NetworkServiceDelegate: class {

    func didCompleteRequest(result: String)
}


class NetworkService: NSObject {

    weak var delegate: NetworkServiceDelegate?

    func fetchDataFromURL(url : String) {
        delegate?.didCompleteRequest(url)
    }
}

Druga klasa:

class ViewController: UIViewController, NetworkServiceDelegate {

    let network = NetworkService()

    override func viewDidLoad() {
        super.viewDidLoad()
        network.delegate = self
        network.fetchDataFromURL("Success!")
    }



    func didCompleteRequest(result: String) {
        print(result)
    }


}
 4
Author: Ekambaram E,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-04-18 07:43:01

Bardzo łatwe krok po kroku (100% pracy i testowane)

Krok 1: Utwórz metodę na kontrolerze pierwszego widoku

 func updateProcessStatus(isCompleted : Bool){
    if isCompleted{
        self.labelStatus.text = "Process is completed"
    }else{
        self.labelStatus.text = "Process is in progress"
    }
}

Krok 2: Ustaw delegata podczas przesuwania do kontrolera drugiego widoku

@IBAction func buttonAction(_ sender: Any) {

    let secondViewController = self.storyboard?.instantiateViewController(withIdentifier: "secondViewController") as! secondViewController
    secondViewController.delegate = self
    self.navigationController?.pushViewController(secondViewController, animated: true)
}

Krok 3: Ustaw delegata jak

Class ViewController: UIViewController,ProcessStatusDelegate {

Krok 4: Utwórz protokół

protocol ProcessStatusDelegate:NSObjectProtocol{
func updateProcessStatus(isCompleted : Bool)
}

Krok 5: weź zmienną

var delegate:ProcessStatusDelegate?

Krok 6: While go powrót do poprzedniego widoku Controller call delegate method so first view controller notify with data

@IBAction func buttonActionBack(_ sender: Any) {
    delegate?.updateProcessStatus(isCompleted: true)
    self.navigationController?.popViewController(animated: true)
}

@IBAction func buttonProgress(_ sender: Any) {
    delegate?.updateProcessStatus(isCompleted: false)
    self.navigationController?.popViewController(animated: true)

}
 4
Author: Mr.Javed Multani,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-03-08 09:41:04

Delegaty są wzorcem projektowym, który pozwala jednemu obiektowi wysyłać wiadomości do innego obiektu, gdy ma miejsce określone zdarzenie. Wyobraź sobie, że obiekt A wywołuje obiekt B, aby wykonać akcję. Po zakończeniu akcji obiekt A powinien wiedzieć, że B wykonał zadanie i podjąć niezbędne działania, można to osiągnąć przy pomocy delegatów! Oto tutorial implementujący delegatów krok po kroku w swift 3

Tutorial Link

 2
Author: James Rochabrun,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-10-31 16:22:34

Prosty Przykład:

protocol Work: class {
    func doSomething()
}

class Manager {
    weak var delegate: Work?
    func passAlong() {
        delegate?.doSomething()
    }
}

class Employee: Work {
    func doSomething() {
        print("Working on it")
    }
}

let manager = Manager()
let developer = Employee()
manager.delegate = developer
manager.passAlong() // PRINTS: Working on it
 1
Author: Bobby,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-07-08 17:35:26

Powyższe rozwiązania wydawały się trochę sprzężone, a jednocześnie unikały ponownego użycia tego samego protokołu w innych kontrolerach, dlatego przyszedłem z rozwiązaniem, które jest mocniejsze wpisane za pomocą generycznego typu-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")    

Wyjście: got new value newValue

 0
Author: Jans,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-01-28 19:04:38

W swift 4.0

Tworzenie delegata na klasie, który musi przesłać pewne dane lub dostarczyć pewne funkcje do innych klas

Jak

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

Po tym w klasie, która zamierza potwierdzić tego delegata

class SnakesAndLadders: GetGameStatus {
    func getPlayerDetails() {

 }
}
 0
Author: Saranjith,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-07-27 04:22:29