Як можна йти про делегата, тобто NSUserNotificationCenterDelegate
швидко?
Як можна йти про делегата, тобто NSUserNotificationCenterDelegate
швидко?
Відповіді:
Він не так відрізняється від obj-c. По-перше, ви повинні вказати протокол у своєму класі декларації, наприклад:
class MyClass: NSUserNotificationCenterDelegate
Реалізація виглядатиме так:
// 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
}
Звичайно, ви повинні встановити делегата. Наприклад:
NSUserNotificationCenter.defaultUserNotificationCenter().delegate = self;
@interface MyCustomClass: UIViewController <ClassIWantToUseDelegate>
полегшити, що дозволяє вам ініціювати / налаштувати viewcontroller, а також викликати методи делегування на підпоглядах? Щось подібне до цього ?
Ось невеличка допомога щодо делегатів між двома контролерами перегляду:
Крок 1. Складіть протокол у UIViewController, який ви будете видаляти / надсилатимуть дані.
protocol FooTwoViewControllerDelegate:class {
func myVCDidFinish(_ controller: FooTwoViewController, text: String)
}
Крок 2. Оголосіть делегата в класі відправлення (тобто UIViewcontroller)
class FooTwoViewController: UIViewController {
weak var delegate: FooTwoViewControllerDelegate?
[snip...]
}
Крок 3. Використовуйте делегат у методі класу, щоб надіслати дані методу прийому, який є будь-яким методом, який приймає протокол.
@IBAction func saveColor(_ sender: UIBarButtonItem) {
delegate?.myVCDidFinish(self, text: colorLabel.text) //assuming the delegate is assigned otherwise error
}
Крок 4: Прийняти протокол у приймальному класі
class ViewController: UIViewController, FooTwoViewControllerDelegate {
Крок 5: Реалізуйте метод делегата
func myVCDidFinish(_ controller: FooTwoViewController, text: String) {
colorLabel.text = "The Color is " + text
controller.navigationController.popViewController(animated: true)
}
Крок 6: Встановіть делегата в PripravForSegue:
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
}
}
І це має працювати. Це, звичайно, лише фрагменти коду, але має дати вам ідею. Для довгого пояснення цього коду ви можете перейти до мого запису в блозі тут:
Якщо вас цікавить, що відбувається під кришкою з делегатом, я написав про це тут:
weak
потрібен лише для занять, а не структури та перерахунки. Якщо делегат буде структурою або перерахунком, то вам не потрібно турбуватися про збереження циклів. Однак делегат свого класу (це справедливо для багатьох випадків, оскільки досить часто це ViewController), тоді вам потрібно, weak
але вам потрібно оголосити свій протокол класом. Більше інформації тут stackoverflow.com/a/34566876/296446
Делегати завжди бентежили мене, поки я не зрозумів, що делегат - це просто клас, який виконує якусь роботу для іншого класу . Це як би там хтось інший, щоб зробити всю брудну роботу за вас, яку ви не хочете робити самі.
Я написав невеличку історію, щоб проілюструвати це. Читайте на дитячому майданчику, якщо вам подобається.
// 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.
На огляді є три ключові частини для створення та використання делегатного шаблону.
Порівняно з нашою вище розповіддю про Bossy Big Brother, делегати часто використовуються для таких практичних застосувань:
Велика частина полягає в тому, що цим класам не потрібно заздалегідь нічого знати один про одного, за винятком того, що клас делегата відповідає необхідному протоколу.
Я настійно рекомендую прочитати наступні дві статті. Вони допомогли мені зрозуміти делегатів навіть краще, ніж це робила документація .
Ще одна примітка
Делегати, які посилаються на інші класи, якими вони не володіють, повинні використовувати weak
ключове слово, щоб уникнути сильних еталонних циклів. Дивіться цю відповідь для отримання більш детальної інформації.
Я отримав кілька виправлень до публікації @MakeAppPie
Перш за все, коли ви створюєте протокол делегата, він повинен відповідати протоколу Class. Як у прикладі нижче.
protocol ProtocolDelegate: class {
func myMethod(controller:ViewController, text:String)
}
По-друге, ваш делегат повинен бути слабким, щоб уникнути збереження циклу.
class ViewController: UIViewController {
weak var delegate: ProtocolDelegate?
}
Нарешті, ви в безпеці, оскільки ваш протокол є необов'язковим значенням. Це означає, що його "нульове" повідомлення не буде надіслано до цього ресурсу. Це схоже на умовне твердження у respondToselector
в objC, але тут у вас є все в одному рядку:
if ([self.delegate respondsToSelector:@selector(myMethod:text:)]) {
[self.delegate myMethod:self text:@"you Text"];
}
Зверху у вас є приклад obj-C, а знизу - приклад Swift, як це виглядає.
delegate?.myMethod(self, text:"your Text")
delegate?.myMethod
не вийде з ладу, тому що якщо делегат - це nil
нічого не станеться. Однак якщо ви помилилися і написали, delegate!.myMethod
ви можете зірватися, якщо делегат не встановлений, то це в основному спосіб для вас бути в безпеці ...
Ось суть, яку я склав. Мені було цікаво те саме, і це допомогло покращити моє розуміння. Відкрийте це на майданчику Xcode, щоб побачити, що відбувається.
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
клас відповідати делегату, який ми зробили? Чи потрібно їх оголосити в одному швидкому файлі? Будь-яка допомога буде означати дуже багато.
class ViewController : UIViewController NameOfDelegate
.
a.swift
відповідно до вашої відповіді вище, він не з'являється b.swift
. Я не можу досягти будь-якого класу поза моїм швидким файлом. якісь тверді?
ДЕЛЕГАТИ В SWIFT 2
Я пояснюю на прикладі Delegate з двома viewControllers. У цьому випадку SecondVC Object повертає дані назад на перший контролер перегляду.
Клас з декларацією протоколу
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)
}
}
У першому протоколі ViewController відповідність здійснюється тут:
class ViewController: UIViewController, getDataDelegate
Визначення методу протоколу в контролері першого перегляду (ViewController)
func getDataFromAnotherVC(temp : String)
{
// dataString from SecondVC
lblForData.text = dataString
}
Під час натискання SecondVC від контролера першого виду (ViewController)
let objectPush = SecondVC()
objectPush.delegateCustom = self
self.navigationController.pushViewController(objectPush, animated: true)
Першокласний:
protocol NetworkServiceDelegate: class {
func didCompleteRequest(result: String)
}
class NetworkService: NSObject {
weak var delegate: NetworkServiceDelegate?
func fetchDataFromURL(url : String) {
delegate?.didCompleteRequest(url)
}
}
Другий клас:
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'
запропонуйте. Це мій шостий день у швидкому :)
Дуже легкий крок за кроком (100% робочий і перевірений)
step1: Створіть метод на контролері першого виду
func updateProcessStatus(isCompleted : Bool){
if isCompleted{
self.labelStatus.text = "Process is completed"
}else{
self.labelStatus.text = "Process is in progress"
}
}
крок 2: Встановіть делегат під час натискання на контролер другого виду
@IBAction func buttonAction(_ sender: Any) {
let secondViewController = self.storyboard?.instantiateViewController(withIdentifier: "secondViewController") as! secondViewController
secondViewController.delegate = self
self.navigationController?.pushViewController(secondViewController, animated: true)
}
step3: встановити делегат, як
клас ViewController: UIViewController, ProcessStatusDelegate {
крок 4: Створення протоколу
protocol ProcessStatusDelegate:NSObjectProtocol{
func updateProcessStatus(isCompleted : Bool)
}
step5: візьміть змінну
var delegate:ProcessStatusDelegate?
крок 6: Поки повертаємось до попереднього методу делегування виклику контролера перегляду, тому спочатку контролер огляду сповіщає дані
@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)
}
Простий приклад:
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
Делегати - це схема дизайну, яка дозволяє одному об’єкту надсилати повідомлення іншому об'єкту, коли відбувається певна подія. Уявіть, що об'єкт A викликає об'єкт B для виконання дії. Після завершення дії об’єкт A повинен знати, що B виконав завдання і вжив необхідних дій, цього можна досягти за допомогою делегатів! Ось підручник із впровадженням делегатів крок за кроком у швидкому 3
Наведені вище рішення виглядали трохи сполученими, і в той же час уникати повторного використання того ж протоколу в інших контролерах, тому я прийшов із рішенням, яке є більш сильним, набраним за допомогою загального стирання типу.
@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")
вихід : отримав нове значення newValue
Створіть делегата класу, якому потрібно надіслати деякі дані або надати певну функціональність іншим класам
Подібно до
protocol GetGameStatus {
var score: score { get }
func getPlayerDetails()
}
Після цього в класі, що збирається підтвердити цього делегата
class SnakesAndLadders: GetGameStatus {
func getPlayerDetails() {
}
}