代表们迅速?


Answers:


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
当您想扩展UIViewController时会发生什么情况,例如,在Objective-C中,您可能会遇到一些麻烦@interface MyCustomClass: UIViewController <ClassIWantToUseDelegate>,即允许您初始化/配置ViewController并在子视图上调用委托方法?与相似吗?
Mahmud Ahmad

1
嗨,亚当,您好快问,如果我不能实例化一个对象,因为它是我无法在另一个类中访问的泛型类,但我想让该泛型类在其中调用函数,该如何实例化对象呢?其他类,因此需要委托吗?
马林

234

这对两个视图控制器之间的委托有一些帮助:

第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委托:FooTwoViewControllerDelegate?PS:代表应该是保留圈子的弱者,孩子应该强烈参考父母
Shial

1
以我的方式,当您将委托设置为可选时,将解决展开错误。委托?.myVCDidFinish因为如果未设置委托,那么cod将不会立即执行:)在您的版本中,它将委托执行,并且如果委托为nil而您将无法解包。
Shial 2014年

4
您需要像这样声明协议,以便使委托协议FooTwoViewControllerDelegate:class {}的弱引用成为可能
2014年

您能否按照每个步骤来设置VC1和VC2之类的VC。我不太确定该放在哪里。
2013年

2
@Shial-实际上似乎有点复杂。 weak仅对于类而不是结构和枚举才需要。如果委托将是一个结构体或枚举,那么您不必担心保留周期。但是,将其委托给一个类(在很多情况下,这是正确的,因为通常是一个ViewController),那么您需要weak但需要将协议声明为一个类。在此处有更多信息stackoverflow.com/a/34566876/296446
Robert

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.

在回顾中,制作和使用委托模式包含三个关键部分。

  1. 定义工人需要做什么的协议
  2. 拥有委托变量的老板类,该变量用于告诉工人类该做什么
  3. 采用协议并执行所需操作的工人类

现实生活

与上面的Bossy Big Brother故事相比,代表通常用于以下实际应用:

  1. 交流:一堂课需要向另一堂课发送一些信息。
  2. 自定义:一个类想允许另一个类对其进行自定义。

最重要的是,这些类不需要相互了解任何东西,除了委托类符合所需的协议。

我强烈建议阅读以下两篇文章。他们帮助我比文档更好地理解了代表。

多一点

引用他们不拥有的其他类的代表应使用weak关键字来避免强引用周期。有关更多详细信息,请参见此答案


3
最后有人可以用常识解释协议和委托!谢啦!
Engineeroholic

当Bossy Big Brother不知道他是哥哥(Generics)时会发生什么?
马林

@Marin,我不太确定我是否理解您的问题。规则列表(协议)不在乎是谁要求遵循规则,或者谁在遵循规则。它们只是规则。
Suragch '16

基本上,我指的是我的问题,此处略有简化。 stackoverflow.com/questions/41195203/…–
马林

47

我对@MakeAppPie的帖子进行了一些更正

首先,当您创建委托协议时,它应该符合Class协议。像下面的例子一样。

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

其次,您的代表应虚弱以避免保留周期。

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

最后,您很安全,因为您的协议是可选值。这意味着其“ nil”消息将不会发送到此属性。它类似于respondToselectorobjC中的条件语句,但是在这里您将所有内容放在一行中:

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

32

这是我总结的要点。我也想知道,这有助于增进我的理解。在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()

喜欢这个。非常有用
Aspen 2015年

@SeeMeCode嗨,首先是一个很好的例子,但我仍然有一个问题。我如何使我的任何UIViewController班级都符合我们所做的委托?是否必须在一个快速文件中声明它们?任何帮助都将非常重要。
法鲁克

@Faruk自从我发布了这篇文章已经有一段时间了,但是我认为您的要求应该非常简单(如果我误会了,我深表歉意)。只需在冒号之后将委托添加到您的UIViewController中即可。像这样class ViewController : UIViewController NameOfDelegate
SeeMeCode '16

@SeeMeCode是的,你很好地回答了我的问题。顺便说一句,我尝试了您的建议,但是当我a.swift根据上面的回答创建一个委托类时,它没有出现b.swift。我无法在swift文件之外的任何课程上上课。有困难吗?
法鲁克

我不明白的一件事是,为什么我应该创建一个新的YelpApi实例,以便我称呼YelpApi的代表?如果正在运行的实例与我刚刚创建的“新”实例不同,该怎么办...它如何知道哪个委托属于YelpApi的哪个实例?
马林

15

SWIFT 2中的代表

我以带有两个viewControllers的Delegate示例为例进行说明。在这种情况下,SecondVC Object将数据发送回第一个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)
    }

}

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

第二类:

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建议。这是我第六天忙碌起来:)
Vaibhav Saran

4

一步一步非常简单(100%的工作和测试)

步骤1:在第一个视图控制器上创建方法

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

步骤2:在推送到第二个视图控制器时设置委托

@IBAction func buttonAction(_ sender: Any) {

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

第三步:设置代表像

ViewController类:UIViewController,ProcessStatusDelegate {

步骤4:建立通讯协定

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

第五步:取一个变量

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

为什么在协议说明中使用关键字“类”?使用和不使用有什么区别?
弗拉德

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 '16

0

在迅速4.0

在需要发送一些数据或为其他类提供某些功能的类上创建一个委托

喜欢

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

之后在课堂上要向该代表确认

class SnakesAndLadders: GetGameStatus {
    func getPlayerDetails() {

 }
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.