Delegaci w swift?
Jak zrobić delegata, czyli NSUserNotificationCenterDelegate
W swift?
12 answers
Nie różni się tak bardzo od obj-c. Najpierw musisz określić protokół w deklaracji klasy, jak poniżej:
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;
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-03-15 04:33:28
Oto mała pomoc na temat delegatów pomiędzy dwoma kontrolerami widoku:
Krok 1: Utwórz protokół w UIViewController, który będzie usuwany/będzie wysyłał dane.
protocol FooTwoViewControllerDelegate:class {
func myVCDidFinish(_ controller: FooTwoViewController, text: String)
}
Krok 2: Zadeklaruj delegata w klasie wysyłającej (np. 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, która jest dowolną metodą, która przyjmuje protokół.
@IBAction func saveColor(_ sender: UIBarButtonItem) {
delegate?.myVCDidFinish(self, text: colorLabel.text) //assuming the delegate is assigned otherwise error
}
Krok 4: Przyjmuje protokół w klasie przyjmują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 preparedforsegue:
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 zadział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ś zainteresowany tym, co dzieje się pod maską z delegat napisałem o tym tutaj:
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-02-05 11:24:47
Delegaci zawsze mnie mylili, dopóki nie zdałem sobie sprawy, że delegat to tylko klasa, która wykonuje jakąś pracę dla innej klasy {4]}. To tak, jakby ktoś inny odwalił za Ciebie brudną robotę, której sam nie chcesz robić.
Napisałem małą historię, aby to zilustrować. Przeczytaj to na Placu Zabaw, jeśli chcesz.
Dawno, dawno temu...// 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.
- the Protokół , który określa, co pracownik musi zrobić
- Klasa boss , która ma zmienną delegata, której używa, aby powiedzieć klasie worker, co ma robić
- klasa robotnicza , która przyjmuje protokół i robi to, co jest wymagane
Prawdziwe życie
W porównaniu do naszej apodyktycznej historii Big Brothera powyżej, delegaci są często używani do następujących praktycznych zastosowań:
-
Komunikacja : jedna klasa musi wysłać jakieś informacje do innej klasy.
- przykład kodu 1: wysyłanie danych z jednego kontrolera widoku do drugiego
- przykład kodu 2: wysyłanie tekstu z niestandardowej klawiatury do pola tekstowego
- dostosowywanie : jedna klasa chce, aby inna klasa mogła ją dostosować.
Najlepsze jest to, że te klasy nie muszą wiedzieć nic o sobie wcześniej, z wyjątkiem tego, że Klasa delegata jest zgodna z wymagany protokół.
[[2]}Gorąco polecam przeczytanie następujących dwóch artykułów. Pomogły mi zrozumieć delegatów jeszcze lepiej niż dokumentacja .- Co To jest Delegacja? – Szybki przewodnik programisty
- jak działa Delegacja-Szybki przewodnik programisty
Jeszcze jedna uwaga
Delegaci, którzy odwołują się do innych klas, których nie posiadają, powinni użyć słowa kluczowego weak
, aby uniknąć silnego odniesienia cykle. Zobacz ta odpowiedź aby uzyskać więcej szczegółów.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:34:40
Dostałem kilka poprawek do posta @MakeAppPie
Po pierwsze, kiedy tworzysz protokół 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ąć cyklu zatrzymania.
class ViewController: UIViewController {
weak var delegate: ProtocolDelegate?
}
Na koniec, jesteś bezpieczny, ponieważ twój protokół jest wartością opcjonalną. Oznacza to, że wiadomość "nil" nie zostanie wysłana do tej właściwości. Jest to podobne do instrukcji warunkowej z respondToselector
w objC, ale tutaj masz wszystko w jednej linii:
if ([self.delegate respondsToSelector:@selector(myMethod:text:)]) {
[self.delegate myMethod:self text:@"you Text"];
}
Powyżej masz przykład obj-C, a poniżej masz szybki przykład, jak to wygląda.
delegate?.myMethod(self, text:"your Text")
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-12-02 15:22:27
Oto gist ułożyłem razem. Zastanawiałam się nad tym samym i to pomogło mi lepiej zrozumieć. 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()
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-12-02 15:25:00
DELEGACI W SWIFT 2
Wyjaśniam przykładem delegata z dwoma viewControllers.In w tym przypadku obiekt SecondVC odsyła dane z powrotem do kontrolera pierwszego 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 pierwszej konfiguracji protokołu ViewController odbywa się tutaj:
class ViewController: UIViewController, getDataDelegate
Definicja metody Protokołu w kontrolerze pierwszego widoku (ViewController)
func getDataFromAnotherVC(dataString : String)
{
// dataString from SecondVC
lblForData.text = dataString
}
Podczas wypychania drugiego kontrolera widoku (ViewController)
let objectPush = SecondVC()
objectPush.delegateCustom = self
self.navigationController.pushViewController(objectPush, animated: true)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-05-13 07:14:53
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)
}
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-04-18 07:43:01
Bardzo łatwe krok po kroku (100% pracy i testowane)
Krok 1: Utwórz metodę na kontrolerze pierwszego 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 przesuwania do kontrolera drugiego widoku
@IBAction func buttonAction(_ sender: Any) {
let secondViewController = self.storyboard?.instantiateViewController(withIdentifier: "secondViewController") as! secondViewController
secondViewController.delegate = self
self.navigationController?.pushViewController(secondViewController, animated: true)
}
Krok 3: 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: While go powrót do poprzedniego widoku Controller call delegate method so first view controller notify with 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)
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-03-08 09:41:04
Delegaty są wzorcem projektowym, który pozwala jednemu obiektowi wysyłać wiadomości do innego obiektu, gdy ma miejsce określone zdarzenie. Wyobraź sobie, że obiekt A wywołuje obiekt B, aby wykonać akcję. Po zakończeniu akcji obiekt A powinien wiedzieć, że B wykonał zadanie i podjąć niezbędne działania, można to osiągnąć przy pomocy delegatów! Oto tutorial implementujący delegatów krok po kroku w swift 3
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-10-31 16:22:34
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
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-07-08 17:35:26
Powyższe rozwiązania wydawały się trochę sprzężone, a jednocześnie unikały ponownego użycia tego samego protokołu w innych kontrolerach, dlatego przyszedłem z rozwiązaniem, które jest mocniejsze wpisane za pomocą generycznego typu-erasure.
@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: got new value newValue
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-01-28 19:04:38
W swift 4.0
Tworzenie delegata na klasie, który musi przesłać pewne dane lub dostarczyć pewne funkcje do innych klas
Jak
protocol GetGameStatus {
var score: score { get }
func getPlayerDetails()
}
Po tym w klasie, która zamierza potwierdzić tego delegata
class SnakesAndLadders: GetGameStatus {
func getPlayerDetails() {
}
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-07-27 04:22:29