Delegasi dengan cepat?


132

Bagaimana cara membuat delegasi, yaitu NSUserNotificationCenterDelegatedengan cepat?


4
Apakah maksud Anda menerapkan delegasi atau mendefinisikan delegasi Anda sendiri?
drewag

Jawaban:


72

Ini tidak jauh berbeda dari obj-c. Pertama, Anda harus menentukan protokol dalam deklarasi kelas Anda, seperti yang berikut:

class MyClass: NSUserNotificationCenterDelegate

Implementasinya akan terlihat seperti berikut:

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

Tentu saja, Anda harus mengatur delegasi. Sebagai contoh:

NSUserNotificationCenter.defaultUserNotificationCenter().delegate = self;

1
Apa yang terjadi ketika Anda ingin memperluas UIViewController, misalnya, dalam objektif-c, Anda dapat memiliki sesuatu yang membuat ini @interface MyCustomClass: UIViewController <ClassIWantToUseDelegate>, memungkinkan Anda untuk init / mengkonfigurasi viewcontroller, serta memanggil metode delegasi pada subviews? Sesuatu yang mirip dengan ini ?
Mahmud Ahmad

1
Hai Adam, pertanyaan singkat, bagaimana saya bisa mengatur delegate = self, jika saya tidak dapat membuat instance objek karena itu adalah kelas generik yang saya tidak memiliki akses ke dalam kelas lain, namun saya ingin kelas generik memanggil fungsi di kelas lain, maka perlunya delegasi?
Marin

234

Berikut sedikit bantuan pada delegasi antara dua pengontrol tampilan:

Langkah 1: Buat protokol di UIViewController yang akan Anda hapus / akan kirim datanya.

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

Langkah2: Deklarasikan delegasi di kelas pengiriman (yaitu UIViewcontroller)

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

Langkah 3: Gunakan delegasi dalam metode kelas untuk mengirim data ke metode penerima, yang merupakan metode apa pun yang mengadopsi protokol.

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

Langkah 4: Adopsi protokol di kelas penerima

class ViewController: UIViewController, FooTwoViewControllerDelegate {

Langkah 5: Terapkan metode delegasi

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

Langkah 6: Tetapkan delegasi di prepForSegue:

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

Dan itu seharusnya berhasil. Ini tentu saja hanya fragmen kode, tetapi harus memberi Anda ide. Untuk penjelasan panjang tentang kode ini, Anda dapat mengunjungi entri blog saya di sini:

segues dan delegasi

Jika Anda tertarik pada apa yang terjadi di bawah tenda dengan seorang delegasi saya menulis tentang itu di sini:

di bawah tenda dengan delegasi


23
Step2 tidakkah seharusnya ada referensi lemah untuk didelegasikan? jika saya benar saya harap edit. Btw Anda bisa menjadikannya nilai opsional. Itu akan lebih cepat. delegasi var lemah: FooTwoViewControllerDelegate? PS: mendelegasikan harus lemah dari mempertahankan lingkaran, anak tidak boleh tetap referensi kuat untuk orang tua
Shial

1
Dengan cara saya ketika Anda akan membuat delegasi opsional, Anda akan menyelesaikan kesalahan Anda membuka. delegate? .myVCDidFinish Menjadi jika delegate tidak mengatur cod tidak akan dijalankan sekarang :) Dalam versi Anda akan mencoba untuk mengeksekusi dan akan gagal membuka jika delegasi adalah nol dan Anda itu.
Shial

4
Anda perlu mendeklarasikan protokol seperti ini untuk membuat referensi yang lemah menjadi mungkin untuk mendelegasikan protokol FooTwoViewControllerDelegate: class {}
codingrhythm

Bisakah Anda mengatur setiap langkah di mana VC Anda seperti VC1 dan VC2. Saya tidak begitu yakin di mana harus menyimpannya.
Cing

2
@ Shial - Sebenarnya sepertinya sedikit rumit. weakhanya diperlukan untuk kelas yang bukan struct dan enum. Jika delegasi akan menjadi struct atau enum maka Anda tidak perlu khawatir tentang mempertahankan siklus. Namun, mendelegasikan sebuah kelas (ini berlaku untuk banyak kasus karena cukup sering dengan ViewController), maka Anda perlu weaktetapi Anda perlu mendeklarasikan protokol Anda sebagai sebuah kelas. Ada info lebih lanjut di sini stackoverflow.com/a/34566876/296446
Robert

94

Delegasi selalu membingungkan saya sampai saya menyadari bahwa seorang delegasi hanyalah sebuah kelas yang berfungsi untuk kelas lain . Ini seperti memiliki orang lain di sana untuk melakukan semua pekerjaan kotor untuk Anda yang tidak ingin Anda lakukan sendiri.

Saya menulis sedikit cerita untuk menggambarkan hal ini. Baca di Taman Bermain jika Anda suka.

Pada suatu ketika...

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

Dalam ulasan, ada tiga bagian utama untuk membuat dan menggunakan pola delegasi.

  1. yang protokol yang mendefinisikan apa yang pekerja perlu dilakukan
  2. yang bos kelas yang memiliki variabel delegasi, yang digunakan untuk memberitahu kelas pekerja apa yang harus dilakukan
  3. yang kelas pekerja yang mengadopsi protokol dan melakukan apa yang diperlukan

Kehidupan nyata

Dibandingkan dengan cerita Bossy Big Brother kami di atas, delegasi sering digunakan untuk aplikasi praktis berikut:

  1. Komunikasi : satu kelas perlu mengirim beberapa informasi ke kelas lain.
  2. Kustomisasi : satu kelas ingin mengizinkan kelas lain untuk menyesuaikannya.

Bagian yang hebat adalah bahwa kelas-kelas ini tidak perlu tahu apa-apa tentang satu sama lain sebelumnya kecuali bahwa kelas delegasi sesuai dengan protokol yang diperlukan.

Saya sangat merekomendasikan membaca dua artikel berikut. Mereka membantu saya memahami delegasi bahkan lebih baik daripada dokumentasi .

Satu catatan lagi

Delegasi yang mereferensikan kelas lain yang tidak mereka miliki harus menggunakan weakkata kunci untuk menghindari siklus referensi yang kuat. Lihat jawaban ini untuk lebih jelasnya.


3
Akhirnya seseorang yang bisa menjelaskan protokol dan mendelegasikan dengan akal sehat! Terima kasih sobat!
Engineeroholic

Apa yang terjadi ketika Bossy Big Brother tidak tahu bahwa dia adalah saudara laki-laki (Generik)?
Marin

@Marin, saya tidak begitu yakin bahwa saya mengerti pertanyaan Anda. Daftar aturan (protokol) tidak peduli siapa yang memanggil aturan untuk diikuti atau siapa yang mengikuti aturan. Itu hanya aturan.
Suragch

Pada dasarnya saya mengacu pada pertanyaan saya, sedikit disederhanakan di sini. stackoverflow.com/questions/41195203/...
Marin

47

Saya mendapat beberapa koreksi untuk dikirim ke @MakeAppPie

Pertama-tama ketika Anda membuat protokol delegasi, protokol tersebut harus sesuai dengan protokol Kelas. Seperti pada contoh di bawah ini.

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

Kedua, delegasi Anda harus lemah untuk menghindari siklus mempertahankan.

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

Terakhir, Anda aman karena protokol Anda adalah nilai opsional. Itu berarti pesan "nihil" tidak akan dikirim ke properti ini. Ini mirip dengan pernyataan kondisional dengan respondToselectordi objC tetapi di sini Anda memiliki semuanya dalam satu baris:

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

Di atas Anda memiliki contoh obj-C dan di bawah Anda memiliki contoh Swift tentang tampilannya.

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

Anda aman karena protokol Anda adalah nilai opsional ..... karena Anda menggunakan perangkaian opsional delegate?.myMethodtidak akan macet karena jika didelegasikan nilmaka tidak akan terjadi apa-apa. Namun jika Anda membuat kesalahan dan menulis delegate!.myMethodAnda bisa crash jika delegasi tidak diatur, jadi pada dasarnya cara Anda aman ...
Honey

33

Inilah intisari yang saya kumpulkan. Saya bertanya-tanya sama dan ini membantu meningkatkan pemahaman saya. Buka ini di Playground Xcode untuk melihat apa yang terjadi.

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

Suka ini. Sangat membantu
Aspen

@SeeMeCode Hai, Itu contoh yang baik pertama, tetapi saya masih memiliki masalah. Bagaimana saya bisa membuat UIViewControllerkelas saya apa saja untuk menyesuaikan delegasi yang kami buat? Apakah mereka harus dinyatakan dalam satu file cepat? Bantuan apa pun akan sangat berarti.
Faruk

@ Faruk Sudah beberapa saat sejak saya memposting ini, tapi saya pikir apa yang Anda minta harus cukup sederhana (Jika saya salah paham, saya minta maaf). Cukup tambahkan delegasi ke UIViewController Anda setelah titik dua. Jadi sesuatu seperti itu class ViewController : UIViewController NameOfDelegate.
SeeMeCode

@SeeMeCode ya, Anda mendapatkan pertanyaan saya dengan baik. Saya mencoba saran Anda, tetapi ketika saya membuat kelas delegasi a.swiftsesuai dengan jawaban Anda di atas, itu tidak muncul b.swift. Saya tidak dapat mencapai kelas apa pun di luar file cepat saya. ada pemikiran?
Faruk

satu hal yang saya tidak mengerti adalah mengapa saya harus membuat instance baru YelpApi supaya saya memanggil delegasi YelpApi? Bagaimana jika instance yang berjalan berbeda dari yang 'baru' yang baru saja saya buat ... bagaimana ia tahu delegasi mana yang dimiliki instance YelpApi mana?
Marin

15

DELEGASI DALAM SWIFT 2

Saya menjelaskan dengan contoh Delegasi dengan dua viewControllers. Dalam hal ini, SecondVC Object mengirim data kembali ke View Controller pertama.

Kelas dengan Deklarasi Protokol

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

}

Dalam protokol ViewController First, penyesuaian dilakukan di sini:

class ViewController: UIViewController, getDataDelegate

Definisi metode protokol di First View Controller (ViewController)

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

Selama mendorong SecondVC dari First View Controller (ViewController)

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

3 baris terakhir Anda membantu saya untuk memahami skenario saya dan menyelesaikan masalah saya. Terima kasih sobat! :)
iHarshil

6

Kelas utama:

protocol NetworkServiceDelegate: class {

    func didCompleteRequest(result: String)
}


class NetworkService: NSObject {

    weak var delegate: NetworkServiceDelegate?

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

Kelas kedua:

class ViewController: UIViewController, NetworkServiceDelegate {

    let network = NetworkService()

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



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


}

pada kompilasi kode di atas itu menunjukkan kesalahan Type 'ViewController' does not conform to protocol 'NetworkServiceDelegate'tlg sarankan. Ini adalah hari ke-6 saya dengan sigap :)
Vaibhav Saran

4

Langkah demi langkah yang sangat mudah (100% berfungsi dan diuji)

langkah1: Buat metode pada pengontrol tampilan pertama

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

step2: Tetapkan delegate sambil mendorong ke controller tampilan kedua

@IBAction func buttonAction(_ sender: Any) {

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

step3: atur suka delegasi

kelas ViewController: UIViewController, ProcessStatusDelegate {

step4: Buat protokol

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

langkah 5: ambil variabel

var delegate:ProcessStatusDelegate?

Langkah 6: Ketika kembali ke metode delegasi panggilan pengendali tampilan sebelumnya, maka pengendali tampilan pertama memberi tahu dengan 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)

}

3

Contoh sederhana:

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

mengapa Anda menggunakan kata kunci "kelas" dalam deskripsi protokol? apa perbedaan dalam menggunakan dan tidak menggunakannya?
Vlad

2
Kata kunci kelas berarti itu hanya protokol kelas. Anda dapat membatasi adopsi protokol ke tipe kelas, dan bukan struktur atau enumerasi, dengan menambahkan kata kunci kelas. Seharusnya saya tidak menambahkannya untuk menghindari kebingungan, tetapi karena Anda bertanya saya akan menyimpannya.
Bobby

2

Delegasi adalah pola desain yang memungkinkan satu objek untuk mengirim pesan ke objek lain ketika peristiwa tertentu terjadi. Bayangkan sebuah objek A memanggil objek B untuk melakukan suatu tindakan. Setelah tindakan selesai, objek A harus tahu bahwa B telah menyelesaikan tugas dan mengambil tindakan yang diperlukan, ini dapat dicapai dengan bantuan delegasi! Berikut ini adalah tutorial penerapan delegasi langkah demi langkah di cepat 3

Tautan Tutorial


0

Solusi di atas tampak sedikit digabungkan dan pada saat yang sama menghindari penggunaan kembali protokol yang sama di pengendali lain, itu sebabnya saya datang dengan solusi yang lebih kuat diketik menggunakan penghapusan tipe generik.

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

output : mendapat nilai baru newValue


Saya tertarik mempelajari lebih lanjut tentang ini. Bisakah Anda menjelaskan lebih lanjut tentang istilah yang Anda gunakan: digabungkan, "hindari penggunaan kembali protokol yang sama", "generic type-erasure". Mengapa mengabstraksikannya seperti ini penting? Haruskah seseorang selalu melakukan ini?
Suragch

0

Di 4.0 cepat

Buat delegasi di kelas yang perlu mengirim beberapa data atau menyediakan fungsionalitas ke kelas lain

Suka

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

Setelah itu di kelas yang akan mengkonfirmasi ke delegasi ini

class SnakesAndLadders: GetGameStatus {
    func getPlayerDetails() {

 }
}
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.