Temsilciler hızlı mı?


132

Bir temsilci nasıl yapılır, yani NSUserNotificationCenterDelegatehızlı bir şekilde?


4
Bir temsilci uygulamak mı yoksa kendi temsilcinizi tanımlamak mı demek istediniz?
drewag

Yanıtlar:


72

Obj-c'den farklı değil. İlk olarak, protokolü sınıf bildiriminizde aşağıdaki gibi belirtmelisiniz:

class MyClass: NSUserNotificationCenterDelegate

Uygulama aşağıdaki gibi görünecektir:

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

Tabii ki, delegeyi ayarlamanız gerekiyor. Örneğin:

NSUserNotificationCenter.defaultUserNotificationCenter().delegate = self;

1
UIViewController'ı genişletmek istediğinizde ne olur, örneğin, obj-c'de, bir şey olabilir, bu @interface MyCustomClass: UIViewController <ClassIWantToUseDelegate>da görünüm denetleyicisini başlatmanıza / yapılandırmanıza ve alt görünümlerde delege yöntemlerini çağırmanıza izin verir mi? Benzer bir şey bu ?
Mahmud Ahmad

1
Merhaba Adam, hızlı soru, delegate = self'i nasıl ayarlayabilirim, eğer bir nesneyi diğer sınıfta erişemediğim genel bir sınıf olduğu için başlatamıyorsam, ama ben generics sınıfının bir işlevi çağırmasını istiyorum diğer sınıf, delege ihtiyacı?
Marin

234

İki görünüm denetleyicisi arasındaki delegelere biraz yardım:

Adım 1: UIViewController'da verileri kaldıracağınız / göndereceğiniz bir protokol yapın.

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

Adım 2: Gönderen sınıfta delege bildirin (yani UIViewcontroller)

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

Adım 3: Verileri, alıcı yöntemi, protokolü benimseyen herhangi bir yöntem göndermek için bir sınıf yönteminde kullanın.

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

Adım 4: Protokolü alıcı sınıfta benimseyin

class ViewController: UIViewController, FooTwoViewControllerDelegate {

5. Adım: Temsilci yöntemini uygulayın

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

Adım 6: Temsilciyi preparForSegue'e ayarlayın:

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

Ve bu işe yaramalı. Bu elbette sadece kod parçalarıdır, ancak size fikir vermelidir. Bu kodun uzun bir açıklaması için buradaki blog girişime gidebilirsiniz:

selamlar ve delegeler

Bir temsilci ile kaputun altında neler olup bittiğini merak ediyorsanız, buraya yazdım:

delegelerle başlık altında


23
2. adım, temsilci için zayıf referans olmamalı mı? eğer haklıysam lütfen düzenleyin. Btw isteğe bağlı değer yapabilirsiniz. Bu daha hızlı olurdu. zayıf var temsilci: FooTwoViewControllerDelegate? PS: delege daire tutmak zayıf cus olmalıdır, çocuk anne
Shial

1
Temsilcimi isteğe bağlı yapacağınız zaman, size çözme hatasını çözeceksiniz. delege cod şimdi yürütmek alışkanlık ayarlanmadıysa Becouse delegate :) Çalıştırmak için çalışacak ve delege nil ve sen ise açmak için başarısız olacaktır.
Shial

4
temsilci protokolü için zayıf referansı mümkün kılmak için böyle bir protokol bildirmeniz gerekir FooTwoViewControllerDelegate: sınıf {}
kodlama ritmi

Lütfen VC'nin VC1 ve VC2 gibi olduğu her bir adımı ayarlayabilir misiniz? Onları nereye koyacağımdan gerçekten emin değilim.
Cing

2
@Shial - Aslında biraz karmaşık görünüyor. weakyalnızca yapılar ve numaralandırmalar için değil sınıflar için gereklidir. Delege bir yapı veya numaralandırma yapacaksa, döngüleri tutma konusunda endişelenmenize gerek yoktur. Ancak, temsilci bir sınıf (bu çoğu zaman bir ViewController beri birçok durumda geçerlidir), o zaman ihtiyacınız weakama protokol olarak bir sınıf olarak ilan etmek gerekir. Burada daha fazla bilgi var stackoverflow.com/a/34566876/296446
Robert

94

Delegeler, bir temsilci sadece başka bir sınıf için iş yapan bir sınıf olduğunu fark edene kadar beni her zaman karıştırdı . Sanki yapmak istemediğiniz tüm kirli işleri sizin için orada yapacak birine sahip olmak gibi.

Bunu açıklamak için küçük bir hikaye yazdım. İsterseniz bir Bahçesi içinde okuyun.

Bir Zamanlar...

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

İncelemede, delege desenini yapmak ve kullanmak için üç anahtar bölüm vardır.

  1. protokol işçisi yapması gereken tanımlar şey bu
  2. işçi sınıfına ne yapacağını söylemek için kullandığı temsilci değişkeni olan patron sınıfı
  3. protokolü benimseyen ve gerekeni yapan işçi sınıfı

Gerçek hayat

Yukarıdaki Bossy Big Brother hikayemize kıyasla, delegeler genellikle aşağıdaki pratik uygulamalar için kullanılır:

  1. İletişim : Bir sınıfın başka bir sınıfa bazı bilgiler göndermesi gerekir.
  2. Özelleştirme : Bir sınıf, başka bir sınıfın onu özelleştirmesine izin vermek istiyor.

Büyük kısmı, delege sınıfının gerekli protokole uyması dışında, bu sınıfların önceden birbirleri hakkında hiçbir şey bilmelerine gerek olmamasıdır.

Aşağıdaki iki makaleyi okumanızı tavsiye ederim. Delegeleri belgelere göre daha iyi anlamama yardımcı oldular .

Bir not daha

Sahip olmadıkları diğer sınıflara başvuran delegeler, weakgüçlü referans döngülerinden kaçınmak için anahtar kelimeyi kullanmalıdır . Daha fazla ayrıntı için bu cevaba bakınız.


3
Sonunda protokol açıklamak ve sağduyu ile delege biri! teşekkürler dostum!
Engineeroholic

Bossy Big Brother onun kardeş olduğunu bilmediğinde ne olur (Jenerikler)?
Marin

@ Marin, sorunuzu anladığımdan gerçekten emin değilim. Kurallar listesi (protokol) kurallara uyulmasını kimin gerektirdiğini ya da kuralları kimin takip ettiğini umursamaz. Onlar sadece kurallar.
Aralık'ta Suragch 5:39

Temelde burada biraz basitleştirilmiş soruma atıfta bulunuyorum. stackoverflow.com/questions/41195203/…
Marin

47

@MakeAppPie yayınlamak için birkaç düzeltme aldım

Öncelikle temsilci protokolü oluştururken Sınıf protokolüne uyması gerekir. Aşağıdaki örnekte olduğu gibi.

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

İkincisi, koruma döngüsünü önlemek için temsilcinizin zayıf olması gerekir.

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

Son olarak, güvendesiniz çünkü protokolünüz isteğe bağlı bir değerdir. Bu, "nil" mesajının bu mülke gönderilmeyeceği anlamına gelir. respondToselectorObjC'deki koşullu ifadeye benzer, ancak burada her şey tek bir satırda var:

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

Yukarıda obj-C örneğiniz var ve aşağıda Swift'in nasıl göründüğüne dair bir örneğiniz var.

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

protokolünüz isteğe bağlı bir değer olduğu için güvendesiniz ... çünkü isteğe bağlı zincirleme kullandığınızda çökmeyeceksiniz delegate?.myMethodçünkü temsilci ise nilhiçbir şey olmaz. Eğer bir hata yaptı ve yazdı Ancak eğer delegate!.myMethodsen olabilir bir temsilci, ayarlı değilse çökmesine tedbirli olmak için onun temelde bir yol ... öylesine
Bal

33

İşte bir araya getirdiğim bir öz . Aynı şeyi merak ediyordum ve bu da anlayışımı geliştirmeye yardımcı oldu. Neler olup bittiğini görmek için bunu bir Xcode Playground'da açın .

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

Bunu sev. Çok yararlı
Aspen

@SeeMeCode Merhaba, Öncelikle iyi bir örnekti, ama hala bir sorunum var. Herhangi bir UIViewControllersınıfımı yaptığımız delege uyacak şekilde nasıl yapabilirim ? Bir hızlı dosyada bildirilmeleri gerekiyor mu? Herhangi bir yardım çok şey ifade edecektir.
Faruk

@ Faruk Bunu yayınladığımdan beri bir süre geçti, ama sorduğunuz şeyin oldukça basit olması gerektiğini düşünüyorum (Yanlış anlıyorsam, özür dilerim). Temsilciyi iki nokta üst üste işaretinden sonra UIViewController'ınıza ekleyin. Yani böyle bir şey class ViewController : UIViewController NameOfDelegate.
SeeMeCode

@SeeMeCode evet, sorumu iyi anladın. Önerinizi btw denedim, ancak a.swiftyukarıdaki cevabınıza göre bir delege sınıfı oluşturduğumda ortaya çıkmıyor b.swift. Hızlı dosyam dışında hiçbir sınıfa ulaşamıyorum. herhangi bir zorluğu var mı?
Faruk

anlamadığım bir şey, neden YelpApi'nin temsilcisini aramam için yeni bir YelpApi örneği oluşturmalıyım? Çalışan örnek az önce oluşturduğum 'yeni' olandan farklıysa ... hangi temsilcinin hangi YelpApi örneğine ait olduğunu nasıl bilebilir?
Marin

15

SWIFT 2'DEKİ DELEGELER

Ben iki viewControllers ile Temsilci örneği ile açıklıyorum.Bu durumda, SecondVC Nesne ilk Görünüm Denetleyicisi'ne veri gönderiyor.

Protokol Bildirimli Sınıf

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

}

İlk ViewController Protokolü'nde uygunluk burada yapılır:

class ViewController: UIViewController, getDataDelegate

İlk Görünüm Denetleyicisindeki (ViewController) protokol yöntemi tanımı

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

SecondVC'yi First View Controller'dan (ViewController) itme sırasında

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

Son 3 satırınız senaryomu anlamama yardımcı oldu ve sorunumu çözdü. Teşekkürler dostum! :)
iHarshil

6

Birinci sınıf:

protocol NetworkServiceDelegate: class {

    func didCompleteRequest(result: String)
}


class NetworkService: NSObject {

    weak var delegate: NetworkServiceDelegate?

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

İkinci sınıf:

class ViewController: UIViewController, NetworkServiceDelegate {

    let network = NetworkService()

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



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


}

yukarıdaki kod derleme hatası Type 'ViewController' does not conform to protocol 'NetworkServiceDelegate'plz önermek gösterir . Hızlı benim 6. gün :)
Vaibhav Saran

4

Adım adım çok kolay (% 100 çalışma ve test edilmiş)

Adım 1: İlk görünüm denetleyicisinde yöntem oluşturma

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

Adım 2: İkinci görünüm denetleyicisine basarken temsilci ayarlama

@IBAction func buttonAction(_ sender: Any) {

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

step3: temsilci gibi ayarla

sınıfı ViewController: UIViewController, ProcessStatusDelegate {

step4: Protokol oluştur

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

step5: bir değişken al

var delegate:ProcessStatusDelegate?

step6: Önceki görünüm denetleyicisine geri dönme delege yöntemini çağırın, böylece ilk görünüm denetleyicisi verileri bildir

@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

Basit Örnek:

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

Neden protokol açıklamasında "class" anahtar sözcüğünü kullanıyorsunuz? kullanmanın ve kullanmamanın farkı nedir?
Vlad

2
Class anahtar sözcüğü, bunun yalnızca bir sınıf protokolü olduğu anlamına gelir. Sınıf anahtar sözcüğünü ekleyerek protokol benimsemeyi yapılara veya numaralandırmalara değil, sınıf türleriyle sınırlandırabilirsiniz. Muhtemelen herhangi bir karışıklığı önlemek için eklememeliydim, ama sorduğunuzdan beri tutacağım.
Bobby

2

Temsilciler, belirli bir olay gerçekleştiğinde bir nesnenin başka bir nesneye mesaj göndermesine izin veren bir tasarım modelidir. A nesnesinin bir eylemi gerçekleştirmek için B nesnesini çağırdığını düşünün. Eylem tamamlandığında, A nesnesi B'nin görevi tamamladığını bilmeli ve gerekli eylemi gerçekleştirmelidir, bu delegelerin yardımıyla gerçekleştirilebilir! İşte hızlı bir şekilde adım adım delegeleri uygulayan bir öğretici

Eğitim Bağlantısı


0

Yukarıdaki çözümler biraz bağlı görünüyordu ve aynı zamanda diğer kontrol cihazlarında aynı protokolü tekrar kullanmaktan kaçındı, bu yüzden genel tip silme kullanarak daha güçlü yazılan çözümle geldim.

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

çıktı : yeni değer var yeniDeğeri


Bununla ilgili daha fazla bilgi edinmek istiyorum. Kullandığınız terimler hakkında daha fazla bilgi verebilir misiniz: birleştiğinde, "aynı protokolü yeniden kullanmaktan kaçının", "genel tür silme". Bu şekilde soyutlamak neden önemlidir? Bunu hep yapmalı mı?
Suresi

0

Hızlı 4.0

Sınıfta, bazı veri göndermesi veya diğer sınıflara bazı işlevler sağlaması gereken bir temsilci oluşturun

Sevmek

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

Bundan sonra sınıfta bu delege onaylayacak

class SnakesAndLadders: GetGameStatus {
    func getPlayerDetails() {

 }
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.