Đại biểu nhanh chóng?


132

Làm thế nào để một người đi về làm một đại biểu, tức là NSUserNotificationCenterDelegatetrong nhanh chóng?


4
Bạn có nghĩa là thực hiện một đại biểu hoặc xác định đại biểu của riêng bạn?
vẽ

Câu trả lời:


72

Nó không khác với obj-c. Đầu tiên, bạn phải chỉ định giao thức trong khai báo lớp, như sau:

class MyClass: NSUserNotificationCenterDelegate

Việc thực hiện sẽ như sau:

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

Tất nhiên, bạn phải thiết lập đại biểu. Ví dụ:

NSUserNotificationCenter.defaultUserNotificationCenter().delegate = self;

1
Điều gì xảy ra khi bạn muốn mở rộng UIViewControll, ví dụ, trong object-c, bạn có thể có một cái gì đó nói dối điều này @interface MyCustomClass: UIViewController <ClassIWantToUseDelegate>, cho phép bạn khởi tạo / cấu hình trình điều khiển khung nhìn, cũng như gọi các phương thức ủy nhiệm trong các cuộc phỏng vấn? Một cái gì đó tương tự như thế này ?
Mahmud Ahmad

1
Xin chào Adam, câu hỏi nhanh, làm cách nào tôi có thể đặt ủy nhiệm = self, nếu tôi không thể khởi tạo một đối tượng vì đây là lớp chung mà tôi không có quyền truy cập trong lớp khác, nhưng tôi muốn lớp tổng quát gọi một hàm trong Các lớp khác, do đó cần đại biểu?
Marin

234

Dưới đây là một chút trợ giúp về các đại biểu giữa hai bộ điều khiển xem:

Bước 1: Tạo giao thức trong UIViewControll mà bạn sẽ xóa / sẽ gửi dữ liệu.

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

Bước2: Khai báo đại biểu trong lớp gửi (tức là UIViewcontroll)

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

Bước 3: Sử dụng ủy nhiệm trong một phương thức lớp để gửi dữ liệu đến phương thức nhận, đây là bất kỳ phương thức nào áp dụng giao thức.

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

Bước 4: Thông qua giao thức trong lớp nhận

class ViewController: UIViewController, FooTwoViewControllerDelegate {

Bước 5: Thực hiện phương thức đại biểu

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

Bước 6: Đặt đại biểu trong phần chuẩn bị:

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

Và điều đó nên làm việc. Tất nhiên đây chỉ là đoạn mã, nhưng sẽ cho bạn ý tưởng. Đối với một lời giải thích dài về mã này, bạn có thể đi đến mục blog của tôi ở đây:

biệt đội và đại biểu

Nếu bạn quan tâm đến những gì đang diễn ra dưới mui xe với một đại biểu tôi đã viết về điều đó ở đây:

dưới mui xe với các đại biểu


23
Bước 2 không nên có tham chiếu yếu để đại biểu? Nếu tôi đúng, xin vui lòng chỉnh sửa nó. Btw bạn có thể làm cho nó giá trị tùy chọn. Điều đó sẽ nhanh hơn. Đại biểu var yếu: FooTwoViewControllDelegate? PS: đại biểu nên yếu về vòng tròn giữ chân, trẻ em không nên tham khảo mạnh mẽ với phụ huynh
Shial

1
Theo cách của tôi khi bạn sẽ làm cho đại biểu tùy chọn, bạn sẽ giải quyết được lỗi chưa xử lý. ủy nhiệm? .myVCDidFinish Trở thành nếu đại biểu không được đặt mã sẽ không thực thi ngay bây giờ :) Trong phiên bản của bạn, nó sẽ cố gắng thực thi và sẽ thất bại nếu đại biểu là không và bạn là như vậy.
Shial

4
bạn cần khai báo giao thức như thế này để có thể tham chiếu yếu cho giao thức ủy nhiệm FooTwoViewControllDelegate: class {}
mã hóa loạn nhịp

Bạn có thể vui lòng đặt theo từng bước trong đó VC bạn giống như VC1 và VC2 không. Tôi không thực sự chắc chắn nơi để đặt chúng.
Cing

2
@Shial - Thật ra nó có vẻ hơi phức tạp. weakchỉ cần thiết cho các lớp không structs và enums. Nếu đại biểu sẽ là một cấu trúc hoặc enum thì bạn không cần phải lo lắng về các chu kỳ giữ lại. Tuy nhiên, ủy nhiệm một lớp của nó (điều này đúng với rất nhiều trường hợp vì khá thường xuyên là ViewContoder), sau đó bạn cần weaknhưng bạn cần khai báo giao thức của mình là một lớp. Có thêm thông tin ở đây stackoverflow.com/a/34566876/296446
Robert

94

Các đại biểu luôn làm tôi bối rối cho đến khi tôi nhận ra rằng một đại biểu chỉ là một lớp làm một số việc cho một lớp khác . Giống như có người khác ở đó để làm tất cả công việc bẩn thỉu cho bạn mà bạn không muốn tự làm.

Tôi đã viết một câu chuyện nhỏ để minh họa điều này. Đọc nó trong Sân chơi nếu bạn thích.

Ngày xửa ngày xưa...

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

Trong đánh giá, có ba phần chính để tạo và sử dụng mẫu đại biểu.

  1. các giao thức mà định nghĩa những gì người lao động cần làm
  2. các lớp sếp rằng có một biến đại biểu, mà nó sử dụng để báo cho giai cấp công nhân phải làm gì
  3. các giai cấp công nhân mà thông qua các giao thức và những gì là cần thiết

Đời thực

So với câu chuyện về Bossy Big Brother của chúng tôi ở trên, các đại biểu thường được sử dụng cho các ứng dụng thực tế sau:

  1. Truyền thông : một lớp cần gửi một số thông tin cho lớp khác.
  2. Tùy biến : một lớp muốn cho phép một lớp khác tùy chỉnh nó.

Phần lớn là các lớp này không cần biết gì về nhau trước ngoại trừ lớp đại biểu tuân thủ giao thức được yêu cầu.

Tôi rất khuyên bạn nên đọc hai bài viết sau. Họ đã giúp tôi hiểu các đại biểu thậm chí còn tốt hơn các tài liệu đã làm.

Thêm một lưu ý

Các đại biểu tham chiếu các lớp khác mà họ không sở hữu nên sử dụng weaktừ khóa để tránh chu kỳ tham chiếu mạnh. Xem câu trả lời này để biết thêm chi tiết.


3
Cuối cùng ai đó có thể giải thích giao thức và ủy thác với ý nghĩa thông thường! cảm ơn người đàn ông
Kỹ sư

Điều gì xảy ra khi Bossy Big Brother không biết anh ấy là anh em (Generics)?
Marin

@Marin, tôi không chắc là tôi hiểu câu hỏi của bạn. Danh sách các quy tắc (giao thức) không quan tâm ai đang kêu gọi các quy tắc được tuân theo hoặc ai đang tuân theo các quy tắc. Họ chỉ là quy tắc.
Suragch

Về cơ bản tôi đang đề cập đến câu hỏi của tôi, hơi đơn giản hóa ở đây. stackoverflow.com/questions/41195203/ trộm
Marin

47

Tôi đã nhận được một vài chỉnh sửa đối với bài đăng của @MakeAppPie

Đầu tiên, khi bạn tạo giao thức ủy nhiệm, nó phải phù hợp với giao thức Class. Giống như trong ví dụ dưới đây.

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

Thứ hai, đại biểu của bạn nên yếu để tránh chu kỳ giữ lại.

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

Cuối cùng, bạn an toàn vì giao thức của bạn là một giá trị tùy chọn. Điều đó có nghĩa là tin nhắn "không" của nó sẽ không được gửi đến tài sản này. Nó tương tự như câu lệnh có điều kiện với respondToselectortrong objC nhưng ở đây bạn có mọi thứ trong một dòng:

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

Ở trên bạn có một ví dụ obj-C và bên dưới bạn có ví dụ Swift về giao diện của nó.

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

bạn an toàn vì giao thức của bạn là một giá trị tùy chọn ..... bởi vì bạn sử dụng chuỗi tùy chọn delegate?.myMethodsẽ không gặp sự cố vì nếu đại biểu là nilkhông có gì sẽ xảy ra. Tuy nhiên, nếu bạn mắc lỗi và viết delegate!.myMethodbạn có thể gặp sự cố nếu một đại biểu không được thiết lập, vì vậy về cơ bản đó là cách để bạn an toàn ...
Honey

32

Đây là một ý chính tôi đặt lại với nhau. Tôi đã tự hỏi tương tự và điều này đã giúp cải thiện sự hiểu biết của tôi. Mở cái này lên trong Xcode Playground để xem chuyện gì đang xảy ra.

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

Thích cái này. Rất hữu ích
Aspen

@SeeMeCode Xin chào, đó là ví dụ đầu tiên, nhưng tôi vẫn có một vấn đề. Làm thế nào tôi có thể làm cho bất kỳ UIViewControllerlớp học của tôi để phù hợp với đại biểu chúng tôi đã thực hiện? Họ có phải được khai báo trong một tập tin nhanh không? Bất kỳ trợ giúp sẽ có rất nhiều ý nghĩa.
Faruk

@Faruk Đã được một lúc kể từ khi tôi đăng bài này, nhưng tôi nghĩ những gì bạn hỏi nên khá đơn giản (Nếu tôi hiểu lầm, tôi xin lỗi). Chỉ cần thêm đại biểu vào UIViewControll của bạn sau dấu hai chấm. Vì vậy, một cái gì đó như class ViewController : UIViewController NameOfDelegate.
SeeMeCode

@SeeMeCode có, bạn hiểu câu hỏi của tôi. Tôi đã thử đề xuất của bạn btw, nhưng khi tôi tạo một lớp đại biểu a.swifttheo câu trả lời của bạn ở trên, nó không xuất hiện b.swift. Tôi không thể đến bất kỳ lớp nào ngoài tập tin nhanh chóng của mình. có khó khăn gì không?
Faruk

một điều tôi không hiểu là tại sao tôi nên tạo một phiên bản mới của YelpApi để tôi gọi cho đại biểu của YelpApi? Điều gì xảy ra nếu phiên bản đang chạy khác với phiên bản 'mới' mà tôi vừa tạo ... làm thế nào để biết đại biểu nào thuộc về phiên bản nào của YelpApi?
Marin

15

GIAO HÀNG TẬN NƠI 2

Tôi đang giải thích với ví dụ về Đại biểu có hai viewControllers. Trong trường hợp này, Đối tượng SecondVC đang gửi dữ liệu trở lại Trình điều khiển Xem đầu tiên.

Lớp có Tuyên bố giao thức

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

}

Trong việc tuân thủ Giao thức ViewControll đầu tiên được thực hiện tại đây:

class ViewController: UIViewController, getDataDelegate

Định nghĩa phương thức giao thức trong Trình điều khiển Chế độ xem Đầu tiên (ViewContoder)

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

Trong quá trình đẩy SecondVC từ Bộ điều khiển Chế độ xem Đầu tiên (ViewContoder)

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

3 dòng cuối cùng của bạn đã giúp tôi hiểu được kịch bản của mình và giải quyết vấn đề của mình. Cảm ơn người đàn ông! :)
iHarshil

6

Lớp học đầu tiên:

protocol NetworkServiceDelegate: class {

    func didCompleteRequest(result: String)
}


class NetworkService: NSObject {

    weak var delegate: NetworkServiceDelegate?

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

Lớp thứ hai:

class ViewController: UIViewController, NetworkServiceDelegate {

    let network = NetworkService()

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



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


}

khi biên dịch mã ở trên, nó hiển thị lỗi Type 'ViewController' does not conform to protocol 'NetworkServiceDelegate'. Đó là ngày thứ 6 của tôi trên swift :)
Vaibhav Saran

4

Từng bước rất dễ dàng (100% làm việc và thử nghiệm)

Bước 1: Tạo phương thức trên trình điều khiển xem đầu tiên

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

Bước2: Đặt ủy nhiệm trong khi đẩy sang bộ điều khiển xem thứ hai

@IBAction func buttonAction(_ sender: Any) {

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

bước 3: thiết lập đại biểu như

lớp ViewContoder: UIViewControll, ProcessStatusDelegate {

bước 4: Tạo giao thức

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

bước 5: lấy một biến

var delegate:ProcessStatusDelegate?

Bước 6: Trong khi quay lại phương thức ủy quyền của trình điều khiển xem trước, vì vậy, lần đầu tiên trình điều khiển xem thông báo với dữ liệu

@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

Ví dụ đơn giản:

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

Tại sao bạn sử dụng từ khóa "lớp" trong mô tả giao thức? sự khác biệt trong việc sử dụng và không sử dụng nó là gì?
Vlad

2
Từ khóa lớp có nghĩa là nó là một giao thức chỉ lớp. Bạn có thể giới hạn việc áp dụng giao thức cho các loại lớp, chứ không phải các cấu trúc hoặc bảng liệt kê, bằng cách thêm từ khóa lớp. Tôi có lẽ không nên thêm nó để tránh bất kỳ sự nhầm lẫn nào, nhưng vì bạn hỏi tôi sẽ giữ.
Bobby

2

Đại biểu là một mẫu thiết kế cho phép một đối tượng gửi tin nhắn đến đối tượng khác khi một sự kiện cụ thể xảy ra. Tưởng tượng một đối tượng A gọi một đối tượng B để thực hiện một hành động. Sau khi hành động hoàn tất, đối tượng A nên biết rằng B đã hoàn thành nhiệm vụ và thực hiện hành động cần thiết, điều này có thể đạt được với sự giúp đỡ của các đại biểu! Dưới đây là hướng dẫn thực hiện các đại biểu từng bước trong swift 3

Liên kết hướng dẫn


0

Các giải pháp ở trên có vẻ hơi phức tạp và đồng thời tránh sử dụng lại cùng một giao thức trong các bộ điều khiển khác, đó là lý do tại sao tôi đi kèm với giải pháp được gõ mạnh hơn bằng cách sử dụng loại xóa chung.

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

đầu ra : có giá trị mới newValue


Tôi thích tìm hiểu thêm về điều này. Bạn có thể giải thích thêm về các thuật ngữ bạn sử dụng: kết hợp, "tránh sử dụng lại cùng một giao thức", "xóa kiểu chung". Tại sao trừu tượng hóa nó như thế này quan trọng? Có nên luôn luôn làm điều này?
Suragch

0

Trong 4.0

Tạo một đại biểu trên lớp cần gửi một số dữ liệu hoặc cung cấp một số chức năng cho các lớp khác

Giống

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

Sau đó trong lớp sẽ xác nhận với đại biểu này

class SnakesAndLadders: GetGameStatus {
    func getPlayerDetails() {

 }
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.