Como se faz para fazer um delegado, ou seja NSUserNotificationCenterDelegate
, rapidamente?
Como se faz para fazer um delegado, ou seja NSUserNotificationCenterDelegate
, rapidamente?
Respostas:
Não é tão diferente de obj-c. Primeiro, você deve especificar o protocolo na sua declaração de classe, como a seguir:
class MyClass: NSUserNotificationCenterDelegate
A implementação terá a seguinte aparência:
// 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
}
Claro, você deve definir o delegado. Por exemplo:
NSUserNotificationCenter.defaultUserNotificationCenter().delegate = self;
@interface MyCustomClass: UIViewController <ClassIWantToUseDelegate>
, permitindo iniciar / configurar o viewcontroller, assim como chamar métodos delegados nas sub-visualizações? Algo semelhante a isso ?
Aqui está uma pequena ajuda para delegados entre dois controladores de exibição:
Etapa 1: faça um protocolo no UIViewController que você removerá / enviará os dados.
protocol FooTwoViewControllerDelegate:class {
func myVCDidFinish(_ controller: FooTwoViewController, text: String)
}
Etapa 2: declarar o delegado na classe de envio (ou seja, UIViewcontroller)
class FooTwoViewController: UIViewController {
weak var delegate: FooTwoViewControllerDelegate?
[snip...]
}
Etapa 3: use o delegado em um método de classe para enviar os dados para o método de recebimento, que é qualquer método que adote o protocolo.
@IBAction func saveColor(_ sender: UIBarButtonItem) {
delegate?.myVCDidFinish(self, text: colorLabel.text) //assuming the delegate is assigned otherwise error
}
Etapa 4: adote o protocolo na classe de recebimento
class ViewController: UIViewController, FooTwoViewControllerDelegate {
Etapa 5: implementar o método delegado
func myVCDidFinish(_ controller: FooTwoViewController, text: String) {
colorLabel.text = "The Color is " + text
controller.navigationController.popViewController(animated: true)
}
Etapa 6: defina o delegado no prepareForSegue:
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
}
}
E isso deve funcionar. Obviamente, isso é apenas fragmentos de código, mas você deve ter uma ideia. Para uma longa explicação desse código, você pode ir até a entrada do meu blog aqui:
Se você está interessado no que está acontecendo sob o capô com um delegado, escrevi sobre isso aqui:
weak
é necessário apenas para classes, não estruturas e enumerações. Se o delegado for uma estrutura ou enum, não será necessário se preocupar com ciclos de retenção. No entanto, o delegado é uma classe (isso ocorre em muitos casos, já que muitas vezes é um ViewController), então você precisa, weak
mas precisa declarar seu protocolo como uma classe. Há mais informações aqui stackoverflow.com/a/34566876/296446
Os delegados sempre me confundiram até perceber que um delegado é apenas uma turma que trabalha para outra turma . É como ter alguém lá para fazer todo o trabalho sujo para você que você não quer fazer sozinho.
Eu escrevi uma pequena história para ilustrar isso. Leia-o no Playground, se quiser.
// 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.
Na revisão, há três partes principais para criar e usar o padrão de delegação.
Em comparação com a história do Bossy Big Brother acima, os delegados são frequentemente usados para as seguintes aplicações práticas:
A grande parte é que essas classes não precisam saber nada uma sobre a outra, exceto que a classe delegada está em conformidade com o protocolo necessário.
Eu recomendo a leitura dos dois artigos a seguir. Eles me ajudaram a entender os delegados ainda melhor do que a documentação .
Mais uma nota
Os delegados que fazem referência a outras classes que não possuem devem usar a weak
palavra-chave para evitar ciclos de referência fortes. Veja esta resposta para mais detalhes.
Recebi algumas correções para publicar no @MakeAppPie
Primeiro, quando você estiver criando um protocolo de delegação, ele deve estar em conformidade com o protocolo de classe. Como no exemplo abaixo.
protocol ProtocolDelegate: class {
func myMethod(controller:ViewController, text:String)
}
Segundo, seu delegado deve ser fraco para evitar o ciclo de retenção.
class ViewController: UIViewController {
weak var delegate: ProtocolDelegate?
}
Por último, você está seguro porque seu protocolo é um valor opcional. Isso significa que sua mensagem "nula" não será enviada para esta propriedade. É semelhante à declaração condicional com respondToselector
em objC, mas aqui você tem tudo em uma linha:
if ([self.delegate respondsToSelector:@selector(myMethod:text:)]) {
[self.delegate myMethod:self text:@"you Text"];
}
Acima, você tem um exemplo de obj-C e, abaixo, um exemplo rápido de como ele se parece.
delegate?.myMethod(self, text:"your Text")
delegate?.myMethod
não trava porque se delegado for nil
, nada aconteceria. No entanto, se você fez erro e escreveu delegate!.myMethod
você pode falhar se um delegado não está definido, então é basicamente uma forma de você para ser seguro ...
Aqui está uma essência que eu montei . Eu estava pensando o mesmo e isso ajudou a melhorar minha compreensão. Abra isso no Xcode Playground para ver o que está acontecendo.
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
classe conheça o delegado que fizemos? Eles precisam ser declarados em um arquivo rápido? Qualquer ajuda significará muito.
class ViewController : UIViewController NameOfDelegate
.
a.swift
acordo com a sua resposta acima, ela não aparece b.swift
. Não consigo alcançar nenhuma classe fora do meu arquivo rápido. algum resistente?
DELEGADOS NO SWIFT 2
Estou explicando com o exemplo de Delegado com dois viewControllers. Nesse caso, o SecondVC Object está enviando dados novamente para o primeiro View Controller.
Classe com declaração de protocolo
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)
}
}
No primeiro protocolo ViewController, a conformidade é feita aqui:
class ViewController: UIViewController, getDataDelegate
Definição de método de protocolo no First View Controller (ViewController)
func getDataFromAnotherVC(temp : String)
{
// dataString from SecondVC
lblForData.text = dataString
}
Durante o push, o SecondVC do First View Controller (ViewController)
let objectPush = SecondVC()
objectPush.delegateCustom = self
self.navigationController.pushViewController(objectPush, animated: true)
Primeira classe:
protocol NetworkServiceDelegate: class {
func didCompleteRequest(result: String)
}
class NetworkService: NSObject {
weak var delegate: NetworkServiceDelegate?
func fetchDataFromURL(url : String) {
delegate?.didCompleteRequest(url)
}
}
Segunda classe:
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'
plz sugerido. É minha 6º dia em rápida :)
Passo a passo muito fácil (100% funcionando e testado)
Etapa 1: Criar método no primeiro controlador de exibição
func updateProcessStatus(isCompleted : Bool){
if isCompleted{
self.labelStatus.text = "Process is completed"
}else{
self.labelStatus.text = "Process is in progress"
}
}
Etapa 2: definir delegado enquanto pressiona para o segundo controlador de exibição
@IBAction func buttonAction(_ sender: Any) {
let secondViewController = self.storyboard?.instantiateViewController(withIdentifier: "secondViewController") as! secondViewController
secondViewController.delegate = self
self.navigationController?.pushViewController(secondViewController, animated: true)
}
step3: defina delegar como
classe ViewController: UIViewController, ProcessStatusDelegate {
etapa 4: criar protocolo
protocol ProcessStatusDelegate:NSObjectProtocol{
func updateProcessStatus(isCompleted : Bool)
}
step5: pegue uma variável
var delegate:ProcessStatusDelegate?
passo 6: Volte ao método anterior de delegação de chamada do controlador de exibição, para que o primeiro visualize o controlador notificando com dados
@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)
}
Exemplo simples:
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
Delegados são um padrão de design que permite que um objeto envie mensagens para outro objeto quando um evento específico acontece. Imagine um objeto A chama um objeto B para executar uma ação. Depois que a ação é concluída, o objeto A deve saber que B concluiu a tarefa e tomar as medidas necessárias, isso pode ser alcançado com a ajuda dos delegados! Aqui está um tutorial implementando delegados passo a passo no rápido 3
As soluções acima pareciam um pouco acopladas e, ao mesmo tempo, evitavam reutilizar o mesmo protocolo em outros controladores, é por isso que eu vim com a solução mais forte digitada usando apagamento de tipo genérico.
@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 : obteve novo valor newValue
Crie um representante na classe que precise enviar alguns dados ou fornecer alguma funcionalidade para outras classes
Gostar
protocol GetGameStatus {
var score: score { get }
func getPlayerDetails()
}
Depois disso, na classe que vai confirmar para este delegado
class SnakesAndLadders: GetGameStatus {
func getPlayerDetails() {
}
}