代理人は迅速ですか?


132

どのようにしてデリゲートを作成するのNSUserNotificationCenterDelegateですか、つまり迅速に?


4
デリゲートを実装するか、独自のデリゲートを定義することを意味しますか?
drewag 2014年

回答:


72

obj-cとそれほど違いはありません。まず、次のようにクラス宣言でプロトコルを指定する必要があります。

class MyClass: NSUserNotificationCenterDelegate

実装は次のようになります。

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

もちろん、デリゲートを設定する必要があります。例えば:

NSUserNotificationCenter.defaultUserNotificationCenter().delegate = self;

1
たとえば、objective-cでUIViewControllerを拡張したい場合はどうなりますか?thisに何かを置くことで@interface MyCustomClass: UIViewController <ClassIWantToUseDelegate>、viewcontrollerを初期化/構成し、サブビューでデリゲートメソッドを呼び出すことができます。これに似たもの
Mahmud Ahmad

1
こんにちはアダム、簡単な質問、他のクラスでアクセスできないジェネリッククラスであるためオブジェクトをインスタンス化できない場合、delegate = selfをどのように設定できますか?ジェネリッククラスで関数を呼び出す必要があります他のクラス、それゆえデリゲートの必要性?
2016

234

2つのView Controller間のデリゲートに関する小さなヘルプを次に示します。

手順1:削除する/データを送信するプロトコルをUIViewControllerで作成します。

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

手順2: 送信クラス(UIViewcontrollerなど)でデリゲートを宣言します。

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

手順3: クラスメソッドでデリゲートを使用して、プロトコルを採用する任意のメソッドである受信メソッドにデータを送信します。

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

ステップ4:受信クラスでプロトコルを採用する

class ViewController: UIViewController, FooTwoViewControllerDelegate {

手順5:デリゲートメソッドを実装する

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

手順6:デリゲートをprepareForSegueに設定します。

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

そして、それはうまくいくはずです。もちろん、これは単なるコードの断片ですが、アイデアがわかるはずです。このコードの詳しい説明については、こちらのブログエントリをご覧ください。

セグエと代議員

デリゲートの内部で何が行われているのか興味がある場合は、ここに書いてあります。

代議員との内部


23
ステップ2デリゲートへの弱い参照があるべきではありませんか?私がそうなら編集してください。ところで、それをオプションの値にすることができます。それはより迅速になります。弱いvar delegate:FooTwoViewControllerDelegate?PS:代理人は保持円の弱い方である必要があり、子供は親を強く参照し続けるべきではありません
シャイール、2014年

1
私の方法では、デリゲートをオプションにするとき、アンラップエラーを解決します。delegate?.myVCDidFinish delegateが設定されていない場合は、cocoは今すぐ実行されません:)ご使用のバージョンでは、実行が試行され、デリゲートがnilである場合、アンラップは失敗します。
Shial、2014年

4
デリゲートプロトコルFooTwoViewControllerDelegate:class {}の弱い参照を可能にするには、このようなプロトコルを宣言する必要があります
コーディングリズム2014年

VCがVC1やVC2のように、各ステップで設定してください。どこに置けばいいのかよくわかりません。
2016年

2
@Shial-実際には少し複雑に見えます。 weak構造体や列挙型ではなく、クラスにのみ必要です。デリゲートが構造体または列挙型になる場合は、保持サイクルを心配する必要はありません。ただし、デリゲートはクラスです(多くの場合はViewControllerであるため、これは多くの場合に当てはまります)weak。必要なプロトコルはクラスとして宣言する必要があります。詳細はこちらStackoverflow.com/a/34566876/296446
ロバート

94

デリゲートは、別のクラスで機能するクラスにすぎないことに気づくまで、デリゲートは常に私を混乱させていました。それは、あなたが自分でやりたくないすべての汚い仕事を他の誰かに依頼するようなものです。

私はこれを説明するために少し話を書きました。必要に応じて、プレイグラウンドで読んでください。

昔々...

// 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.

復習すると、デリゲートパターンの作成と使用には3つの重要な部分があります。

  1. ワーカーが何をする必要があるかを定義するプロトコル
  2. ボスクラス、それが何をすべきか、ワーカークラスを伝えるために使用するデリゲート変数を持っています、
  3. プロトコルを採用し、必要なことを行うワーカークラス

実生活

上記のBossy Big Brotherのストーリーと比較すると、デリゲートは次の実用的なアプリケーションによく使用されます。

  1. コミュニケーション:あるクラスは別のクラスに情報を送信する必要があります。
  2. カスタマイズ:あるクラスが別のクラスにカスタマイズを許可したい。

大きな部分は、デリゲートクラスが必要なプロトコルに準拠していることを除いて、これらのクラスが事前にお互いについて何も知る必要がないことです。

次の2つの記事を読むことを強くお勧めします。これらは、ドキュメントよりも代理人を理解するのに役立ちました。

もう一つのメモ

所有していない他のクラスを参照するデリゲートは、weak強い参照サイクルを回避するためにキーワードを使用する必要があります。詳細については、この回答を参照してください。


3
最後に、プロトコルを説明して常識的に委任できる人!ありがとう!
Engineeroholic

Bossy Big Brotherが彼がGenericsであることを知らないとどうなりますか?
マリン2016

@Marin、私はあなたの質問を理解しているかどうか本当にわかりません。ルールのリスト(プロトコル)は、ルールの実行を要求しているのが誰なのか、またはルールを誰が実行しているのかは関係ありません。彼らは単なるルールです。
Suragch 2016

基本的に私は私の質問を参照していますが、ここでは少し簡略化しています。 stackoverflow.com/questions/41195203/...
マリン

47

@MakeAppPieの投稿にいくつか修正を加えました

最初に、デリゲートプロトコルを作成するときは、クラスプロトコルに準拠する必要があります。以下の例のように。

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

第2に、保持サイクルを回避するためにデリゲートを弱くする必要があります。

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

最後に、プロトコルはオプションの値なので、安全です。つまり、「nil」メッセージはこのプロパティに送信されません。これrespondToselectorはobjCでの条件付きステートメントに似ていますが、ここでは1行にすべてが含まれています。

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

上にobj-Cの例があり、下にSwiftの例があります。

delegate?.myMethod(self, text:"your Text")

プロトコルはオプションの値なので安全です .....オプションのチェーンを使用するdelegate?.myMethodとクラッシュしないので、デリゲートを使用するとnil何も起こりません。ただし、間違って作成した場合、デリゲートが設定されていないとクラッシュdelegate!.myMethodする可能性があるため、基本的には安全な方法です
Honey

33

これが私がまとめた要点です。同じことを考えていたので、理解が深まりました。これをXcode Playgroundで開いて、何が起こっているかを確認します。

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

これが大好き。非常に役立つ
アスペン

@SeeMeCodeこんにちは、最初は良い例でしたが、まだ問題があります。作成したUIViewControllerデリゲートに準拠するようにクラスを作成するにはどうすればよいですか?それらは1つの迅速なファイルで宣言する必要がありますか?どんな助けも意味があります。
Faruk

@Farukこれを投稿してからしばらく経ちますが、あなたの質問はかなり単純なものにすべきだと思います(誤解している場合は、謝罪します)。デリゲートをコロンの後にUIViewControllerに追加するだけです。ので、のようなものclass ViewController : UIViewController NameOfDelegate
SeeMeCode

@SeeMeCodeはい、あなたは私の質問をうまく聞きました。ところであなたの提案を試してみましたが、a.swift上記の答えに従ってデリゲートクラスを作成すると、で表示されませんb.swift。Swiftファイル以外のクラスにはアクセスできません。どんな考え?
Faruk

私が理解していないことの1つは、YelpApiのデリゲートを呼び出すために、なぜYelpApiの新しいインスタンスを作成する必要があるのか​​です。実行中のインスタンスが、作成したばかりの「新しい」インスタンスと異なる場合はどうなりますか?どのデリゲートがYelpApiのどのインスタンスに属するかをどのようにして知るのですか?
Marin

15

SWIFT 2のデリゲート

2つのviewControllerを持つデリゲートの例で説明します。この場合、SecondVCオブジェクトは最初のView Controllerにデータを送り返しています。

プロトコル宣言付きのクラス

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

}

最初のViewControllerプロトコルでの適合はここで行われます:

class ViewController: UIViewController, getDataDelegate

First View Controller(ViewController)でのプロトコルメソッド定義

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

First View Controller(ViewController)からのSecondVCのプッシュ中

let objectPush = SecondVC()
objectPush.delegateCustom = self
self.navigationController.pushViewController(objectPush, animated: true)

最後の3行は、私のシナリオを理解し、問題を解決するのに役立ちました。ありがとう!:)
iHarshil

6

ファーストクラス:

protocol NetworkServiceDelegate: class {

    func didCompleteRequest(result: String)
}


class NetworkService: NSObject {

    weak var delegate: NetworkServiceDelegate?

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

2番目のクラス:

class ViewController: UIViewController, NetworkServiceDelegate {

    let network = NetworkService()

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



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


}

上記のコードをコンパイルすると、エラーType 'ViewController' does not conform to protocol 'NetworkServiceDelegate'plzが表示されます。それは迅速な私の6日目です:)
Vaibhav Saran

4

ステップバイステップで非常に簡単(100%動作し、テスト済み)

ステップ 1 最初のView Controllerでメソッドを作成する

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

ステップ2: 2番目のビューコントローラーにプッシュしながらデリゲートを設定する

@IBAction func buttonAction(_ sender: Any) {

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

ステップ3:デリゲートを次のように設定する

クラスViewController:UIViewController、ProcessStatusDelegate {

ステップ4:プロトコルを作成する

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

ステップ5:変数を取る

var delegate:ProcessStatusDelegate?

ステップ6:前のビューコントローラーに戻る間、デリゲートメソッドを呼び出すため、最初のビューコントローラーはデータで通知します

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

}

3

簡単な例:

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

プロトコルの説明でキーワード「class」を使用する理由 それを使用することと使用しないことの違いは何ですか?
Vlad

2
classキーワードは、それがクラスのみのプロトコルであることを意味します。classキーワードを追加することで、プロトコルの採用を構造体や列挙型ではなくクラスタイプに制限できます。混乱を避けるためにそれを追加するべきではなかったと思いますが、あなたが尋ねたので続けます。
ボビー

2

デリゲートは、特定のイベントが発生したときに、あるオブジェクトが別のオブジェクトにメッセージを送信できるようにする設計パターンです。オブジェクトAがオブジェクトBを呼び出してアクションを実行するとします。アクションが完了すると、オブジェクトAはBがタスクを完了したことを認識し、必要なアクションを実行する必要があります。これはデリゲートの助けを借りて達成できます!以下は、Swift 3でデリゲートを段階的に実装するチュートリアルです。

チュートリアルリンク


0

上記のソリューションは少し関連しているように見え、同時に他のコントローラーで同じプロトコルを再利用することを避けています。そのため、私はジェネリック型消去を使用してより強い型付けのソリューションを用意しました。

@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")    

出力新しい値を取得しましたnewValue


これについてもっと知りたいです。使用する用語について詳しく説明していただけますか:結合、「同じプロトコルの再利用を避ける」、「一般的な型消去」。なぜこのように抽象化することが重要なのですか?常にこれを行う必要がありますか?
Suragch 2016

0

Swift 4.0では

一部のデータを送信するか、他のクラスにいくつかの機能を提供する必要があるクラスにデリゲートを作成する

お気に入り

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

その後、このデリゲートに確認するクラスで

class SnakesAndLadders: GetGameStatus {
    func getPlayerDetails() {

 }
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.