Jak zabrać się za delegowanie, tj. NSUserNotificationCenterDelegate
Szybko?
Jak zabrać się za delegowanie, tj. NSUserNotificationCenterDelegate
Szybko?
Odpowiedzi:
Nie różni się zbytnio od obj-c. Najpierw musisz określić protokół w swojej deklaracji klasy, na przykład:
class MyClass: NSUserNotificationCenterDelegate
Implementacja będzie wyglądać następująco:
// 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
}
Oczywiście musisz ustawić delegata. Na przykład:
NSUserNotificationCenter.defaultUserNotificationCenter().delegate = self;
@interface MyCustomClass: UIViewController <ClassIWantToUseDelegate>
, co pozwala na zainicjowanie / skonfigurowanie kontrolera widoku, a także wywołanie metod delegata na podglądzie? Coś podobnego do tego ?
Oto mała pomoc dotycząca delegatów między dwoma kontrolerami widoku:
Krok 1: Stwórz protokół w UIViewController, który usuniesz / będziesz wysyłać dane.
protocol FooTwoViewControllerDelegate:class {
func myVCDidFinish(_ controller: FooTwoViewController, text: String)
}
Krok 2: Zadeklaruj delegata w klasie wysyłającej (tj. UIViewcontroller)
class FooTwoViewController: UIViewController {
weak var delegate: FooTwoViewControllerDelegate?
[snip...]
}
Krok 3: Użyj delegata w metodzie klasowej, aby wysłać dane do metody odbierającej, czyli dowolnej metody, która przyjmuje protokół.
@IBAction func saveColor(_ sender: UIBarButtonItem) {
delegate?.myVCDidFinish(self, text: colorLabel.text) //assuming the delegate is assigned otherwise error
}
Krok 4: Przyjęcie protokołu w klasie odbierającej
class ViewController: UIViewController, FooTwoViewControllerDelegate {
Krok 5: Zaimplementuj metodę delegata
func myVCDidFinish(_ controller: FooTwoViewController, text: String) {
colorLabel.text = "The Color is " + text
controller.navigationController.popViewController(animated: true)
}
Krok 6: Ustaw delegata w pliku PrzygotowanieForSegue:
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
}
}
I to powinno działać. To oczywiście tylko fragmenty kodu, ale powinno dać ci pomysł. Aby uzyskać długie wyjaśnienie tego kodu, możesz przejść do mojego wpisu na blogu tutaj:
Jeśli jesteście ciekawi co się dzieje pod maską z delegatem to napisałem o tym tutaj:
weak
jest potrzebny tylko w przypadku klas, a nie struktur i wyliczeń. Jeśli delegat ma być strukturą lub wyliczeniem, nie musisz się martwić o zachowanie cykli. Jednak delegat jest klasą a (jest to prawdą w wielu przypadkach, ponieważ dość często jest to ViewController), wtedy potrzebujesz, weak
ale musisz zadeklarować swój protokół jako klasę. Więcej informacji można znaleźć tutaj stackoverflow.com/a/34566876/296446
Delegaci zawsze wprawiali mnie w zakłopotanie, dopóki nie zdałem sobie sprawy, że delegat to tylko klasa, która wykonuje jakąś pracę dla innej klasy . To tak, jakby ktoś inny wykonywał za Ciebie całą brudną robotę, której nie chcesz wykonywać samodzielnie.
Napisałem krótką historię, aby to zilustrować. Przeczytaj to na placu zabaw, jeśli chcesz.
// 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.
W przeglądzie istnieją trzy kluczowe części tworzenia i używania wzorca delegata.
W porównaniu z powyższą historią Bossy Big Brother, delegaci są często wykorzystywani do następujących praktycznych zastosowań:
Wspaniałą częścią jest to, że te klasy nie muszą wcześniej nic o sobie wiedzieć, z wyjątkiem tego, że klasa delegatów jest zgodna z wymaganym protokołem.
Gorąco polecam przeczytanie poniższych dwóch artykułów. Pomogli mi zrozumieć delegatów nawet lepiej niż dokumentacja .
Jeszcze jedna uwaga
Delegaci odwołujący się do innych klas, których nie są właścicielami, powinni używać weak
słowa kluczowego, aby uniknąć silnych cykli odwołań. Zobacz tę odpowiedź, aby uzyskać więcej informacji.
Mam kilka poprawek do posta @MakeAppPie
Po pierwsze, podczas tworzenia protokołu delegata powinien on być zgodny z protokołem klasy. Jak w przykładzie poniżej.
protocol ProtocolDelegate: class {
func myMethod(controller:ViewController, text:String)
}
Po drugie, twój delegat powinien być słaby, aby uniknąć zatrzymania cyklu.
class ViewController: UIViewController {
weak var delegate: ProtocolDelegate?
}
Wreszcie, jesteś bezpieczny, ponieważ Twój protokół jest wartością opcjonalną. Oznacza to, że jego wiadomość „nil” nie zostanie wysłana do tej właściwości. Jest podobny do instrukcji warunkowej z respondToselector
w objC, ale tutaj masz wszystko w jednym wierszu:
if ([self.delegate respondsToSelector:@selector(myMethod:text:)]) {
[self.delegate myMethod:self text:@"you Text"];
}
Powyżej znajduje się przykład obj-C, a poniżej przykład języka Swift, jak to wygląda.
delegate?.myMethod(self, text:"your Text")
delegate?.myMethod
, nie ulegnie awarii, ponieważ jeśli delegat jest, nil
to nic się nie stanie. Jednak jeśli się pomylisz i napisał delegate!.myMethod
pan mógł upaść, jeżeli pełnomocnik nie jest ustawiona, więc jej w zasadzie sposobem, aby być bezpieczne ...
Oto streszczenie, które zebrałem. Zastanawiałem się nad tym samym, co pomogło mi w lepszym zrozumieniu. Otwórz to w Xcode Playground, aby zobaczyć, co się dzieje.
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()
UIViewController
klasa była zgodna z delegatem, którego stworzyliśmy? Czy muszą być zadeklarowane w jednym szybkim pliku? Każda pomoc będzie wiele znaczyć.
class ViewController : UIViewController NameOfDelegate
.
a.swift
zgodnie z twoją odpowiedzią powyżej, nie pojawia się b.swift
. Nie mogę dotrzeć do żadnej klasy poza moim szybkim plikiem. jakieś trudności?
DELEGACI W SWIFT 2
Wyjaśniam na przykładzie Delegata z dwoma ViewControllers.W tym przypadku obiekt SecondVC wysyła dane z powrotem do pierwszego kontrolera widoku.
Klasa z deklaracją protokołu
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)
}
}
W First ViewController zgodność z protokołem odbywa się tutaj:
class ViewController: UIViewController, getDataDelegate
Definicja metody protokołu w kontrolerze First View (ViewController)
func getDataFromAnotherVC(temp : String)
{
// dataString from SecondVC
lblForData.text = dataString
}
Podczas wypychania SecondVC z kontrolera pierwszego widoku (ViewController)
let objectPush = SecondVC()
objectPush.delegateCustom = self
self.navigationController.pushViewController(objectPush, animated: true)
Pierwsza klasa:
protocol NetworkServiceDelegate: class {
func didCompleteRequest(result: String)
}
class NetworkService: NSObject {
weak var delegate: NetworkServiceDelegate?
func fetchDataFromURL(url : String) {
delegate?.didCompleteRequest(url)
}
}
Druga klasa:
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'
sugeruje plz. To mój szósty dzień na szybkim :)
Bardzo łatwe krok po kroku (w 100% sprawne i przetestowane)
krok 1: Utwórz metodę na pierwszym kontrolerze widoku
func updateProcessStatus(isCompleted : Bool){
if isCompleted{
self.labelStatus.text = "Process is completed"
}else{
self.labelStatus.text = "Process is in progress"
}
}
Krok 2: ustaw delegata podczas wypychania do drugiego kontrolera widoku
@IBAction func buttonAction(_ sender: Any) {
let secondViewController = self.storyboard?.instantiateViewController(withIdentifier: "secondViewController") as! secondViewController
secondViewController.delegate = self
self.navigationController?.pushViewController(secondViewController, animated: true)
}
step3: ustaw delegata jak
class ViewController: UIViewController, ProcessStatusDelegate {
krok 4: Utwórz protokół
protocol ProcessStatusDelegate:NSObjectProtocol{
func updateProcessStatus(isCompleted : Bool)
}
krok 5: weź zmienną
var delegate:ProcessStatusDelegate?
Krok 6: Podczas gdy wróć do poprzedniego widoku metody delegata wywołania kontrolera, najpierw wyświetl powiadomienie kontrolera z danymi
@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)
}
Prosty przykład:
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
Delegaci to wzorzec projektowy, który umożliwia jednemu obiektowi wysyłanie komunikatów do innego obiektu, gdy ma miejsce określone zdarzenie. Wyobraź sobie, że obiekt A wywołuje obiekt B, aby wykonać akcję. Po zakończeniu działania obiekt A powinien wiedzieć, że B wykonał zadanie i podjąć niezbędne działania, można to osiągnąć z pomocą delegatów! Oto samouczek implementujący delegatów krok po kroku w Swift 3
Powyższe rozwiązania wydawały się nieco powiązane, a jednocześnie unikały ponownego użycia tego samego protokołu w innych kontrolerach, dlatego przyszedłem z rozwiązaniem, które jest silniej wpisywane przy użyciu ogólnego wymazywania typów.
@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")
wyjście : otrzymano nową wartość newValue
Utwórz delegata w klasie, która musi wysyłać dane lub udostępniać funkcje innym klasom
Lubić
protocol GetGameStatus {
var score: score { get }
func getPlayerDetails()
}
Potem w klasie, która potwierdzi delegatowi
class SnakesAndLadders: GetGameStatus {
func getPlayerDetails() {
}
}