신속한 대의원?


132

NSUserNotificationCenterDelegate신속한 대의원을 만드는 방법은 무엇입니까?


4
대리인을 구현하거나 자신의 대리인을 정의하는 것을 의미합니까?
drewag

답변:


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를 확장하고 싶을 때 어떤 일이 발생 @interface MyCustomClass: UIViewController <ClassIWantToUseDelegate>하여 뷰 컨트롤러를 초기화 / 구성하고 하위 뷰에서 대리자 메서드를 호출 할 수 있습니까? 이것 과 비슷한 것 ?
Mahmud Ahmad

1
안녕하세요 Adam, 빠른 질문입니다. 다른 클래스에서 액세스 할 수없는 일반 클래스이기 때문에 객체를 인스턴스화 할 수없는 경우 delegate = self를 설정하는 방법은 있지만 generics 클래스는 함수를 호출하기를 원합니다. 다른 클래스, 따라서 대표가 필요합니까?
Marin

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 단계 : PreparingForSegue에서 대리인을 설정합니다.

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
Step2 위임에 대한 약한 참조가 없어야합니까? 내가 맞다면 편집하십시오. Btw는 선택적인 값으로 만들 수 있습니다. 더 빠를 것입니다. 약한 var 대리자 : FooTwoViewControllerDelegate? 추신 : 대리인은 원 유지의 약한 원인이어야합니다, 아이는 부모에 대한 강한 참조를 유지해야합니다
Shial

1
내 방식대로 델리게이트를 선택적으로 만들면 랩 해제 오류가 해결됩니다. delegate? .myVCDidFinish delegate가 설정되어 있지 않으면 대구가 지금 실행되지 않습니다.
Shial

4
당신이 위임 프로토콜 FooTwoViewControllerDelegate에 대한 약한 참조 가능하게하기 위해 다음과 같은 프로토콜을 선언해야 클래스를 {}
codingrhythm

VC가 VC1 및 VC2와 같은 각 단계에서 설정해 주시겠습니까? 어디에 넣을지 잘 모르겠습니다.
의 cing

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가 자신이 형제 (제네릭)임을 모르면 어떻게됩니까?
Marin

@Marin, 나는 당신의 질문을 이해했는지 잘 모르겠습니다. 규칙 목록 (프로토콜)은 규칙을 준수해야하는 사람 또는 규칙을 따르는 사람을 신경 쓰지 않습니다. 그들은 단지 규칙입니다.
Suragch

기본적으로 나는 내 질문을 언급하고 있으며 여기에서 약간 단순화되었습니다. stackoverflow.com/questions/41195203/…
마린

47

@MakeAppPie의 게시물에 대한 수정 사항이 거의 없습니다.

먼저 위임 프로토콜을 만들 때 클래스 프로토콜을 준수해야합니다. 아래 예와 같이.

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

@SeeMeCode 안녕하세요, 처음에는 좋은 예 였지만 여전히 문제가 있습니다. UIViewController우리가 만든 대의원을 준수하기 위해 수업을 어떻게 만들 수 있습니까? 하나의 신속한 파일로 선언해야합니까? 도움이 필요합니다.
Faruk

@Faruk이 글을 게시한지 오래되었습니다 만, 요청하신 내용이 매우 간단해야한다고 생각합니다 (오해가 있다면 사과드립니다). 콜론 다음에 UIViewController에 대리자를 추가하십시오. 그래서 같은 class ViewController : UIViewController NameOfDelegate.
SeeMeCode

@SeeMeCode 예, 당신은 내 질문을 잘 받았습니다. btw 제안을 시도했지만 a.swift위의 답변 에 따라 델리게이트 클래스를 만들면에 표시 되지 않습니다 b.swift. 신속한 파일 이외의 다른 수업에 도달 할 수 없습니다. 어떤 어려움?
Faruk

내가 이해하지 못하는 한 가지는 YelpApi의 대리인에게 전화를 걸기 위해 YelpApi의 새 인스턴스를 만들어야하는 이유는 무엇입니까? 실행중인 인스턴스가 방금 생성 한 '새'인스턴스와 다른 경우 어떻게해야합니다. YelpApi 인스턴스에 속하는 델리게이트를 어떻게 알 수 있습니까?
마린

15

스위프트 2의 대표단

두 개의 viewController가있는 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)
    }

}

첫 번째 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 2016 년

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

3 단계 : 대표를 다음과 같이 설정

ViewController 클래스 : UIViewController, ProcessStatusDelegate {

4 단계 : 프로토콜 생성

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

step5 : 변수를 가져 가라

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 키워드를 추가하여 프로토콜 채택을 구조 또는 열거가 아닌 클래스 유형으로 제한 할 수 있습니다. 혼란을 피하기 위해 추가하지 않았을 수도 있지만 요청한 이후 계속 유지하겠습니다.
Bobby

2

대리인은 특정 이벤트가 발생할 때 한 개체가 다른 개체에 메시지를 보낼 수 있도록하는 디자인 패턴입니다. 객체 A가 객체 B를 호출하여 동작을 수행한다고 상상해보십시오. 조치가 완료되면 오브젝트 A는 B가 태스크를 완료하고 필요한 조치를 취했음을 알고 있어야합니다. 이는 델리게이트의 도움으로 달성 할 수 있습니다! 다음은 신속한 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

0

스위프트 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.