Swift 3'te nasıl özel bildirimler oluşturursunuz?


Yanıtlar:


32

Bunun için bir protokol de kullanabilirsiniz.

protocol NotificationName {
    var name: Notification.Name { get }
}

extension RawRepresentable where RawValue == String, Self: NotificationName {
    var name: Notification.Name {
        get {
            return Notification.Name(self.rawValue)
        }
    }
}

Ve sonra bildirim adlarınızı enumistediğiniz yerde tanımlayın . Örneğin:

class MyClass {
    enum Notifications: String, NotificationName {
        case myNotification
    }
}

Ve gibi kullan

NotificationCenter.default.post(name: Notifications.myNotification.name, object: nil)

Bu şekilde, bildirim adları Vakıftan ayrılacaktır Notification.Name. Ve Notification.Namedeğişikliklerin uygulanması durumunda sadece protokolünüzü değiştirmeniz gerekecektir .


Bu tam olarak başlangıçta çalışması gerektiğini düşündüğüm yol - bildirimler numaralandırılmalıdır. Hile için teşekkürler!
hexdreamer

Sorun değil! Ben uzantının yapısını içerecek şekilde kodunu düzenledi NotificationNameyüzden nameözellik yalnızca protokole uyan çeteleler eklenir.
halil_g

Kesinlikle eşdeğer ancak daha mantıklı IMO, uzantıyı NotificationName'de (RawRepresentable yerine) şu şekilde tanımlayabilirsiniz:extension NotificationName where Self: RawRepresentable, Self.RawValue == String {
jlj

388

Bunu başarmanın daha temiz (bence) bir yolu var

extension Notification.Name {

    static let onSelectedSkin = Notification.Name("on-selected-skin")
}

Ve sonra bunu böyle kullanabilirsin

NotificationCenter.default.post(name: .onSelectedSkin, object: selectedSkin)

2
Yukarıdaki kodu kullanıyorum. Bu statik bir özelliktir.
Cesar Varela

3
Çok temiz, çok seviyorum
Tom Wolters

10
extension NSNotification.Name yerine extension Notification.Name . Aksi takdirde Swift 3 ile ilgili şikayetler'Notification' is ambiguous for type lookup in this context
lluisgh

9
Dizide bir yazım hatası yaptığım ve böylece yazılan bildirim adlarının değerini gösterdiğim için olumlu oyumu alırsınız: P
Dorian Roy

10
Apple tarafından WWDC 2016 Session 207'de önerilen yöntemin bu olduğunu belirtmekte fayda var. Developer.apple.com/videos/play/wwdc2016/207
Leon

36

Notification.post şu şekilde tanımlanır:

public func post(name aName: NSNotification.Name, object anObject: AnyObject?)

Objective-C'de, bildirim adı düz bir NSString'dir. Swift'de NSNotification.Name olarak tanımlanır.

NSNotification.Name şu şekilde tanımlanır:

public struct Name : RawRepresentable, Equatable, Hashable, Comparable {
    public init(_ rawValue: String)
    public init(rawValue: String)
}

Bu biraz tuhaf, çünkü onun bir Enum olmasını beklerdim ve görünüşte daha fazla yararı olmayan özel bir yapı değil.

Notification for NSNotification'da bir tür takma adı vardır.

public typealias Name = NSNotification.Name

Kafa karıştıran kısım, Swift'de hem Bildirim hem de NSNotification'ın mevcut olmasıdır.

Bu nedenle, kendi özel bildiriminizi tanımlamak için aşağıdakilere benzer bir şey yapın:

public class MyClass {
    static let myNotification = Notification.Name("myNotification")
}

Sonra onu aramak için:

NotificationCenter.default().post(name: MyClass.myNotification, object: self)

3
İyi cevap. Bazı yorumlar: Bu biraz garip, çünkü bir Enum olmasını beklerdim - Bir enum kapalı bir kümedir . Bir sıralama Notification.Nameolsaydı, hiç kimse yeni bildirimler tanımlayamazdı. Yeni üyelerin eklenmesine izin vermesi gereken, aksi takdirde enum benzeri türler için yapılar kullanıyoruz. ( Hızlı evrim önerisine bakın .)
rickster

2
Kafa karıştıran kısım, Swift'de hem Bildirim hem de NSNotification'ın var olmasıdır - Notificationbir değer türüdür (yapı), böylece Swift'in değer (im) değişkenliği için anlambiliminden faydalanabilir. Genel olarak, Temel türleri Swift 3'te "NS" değerlerini düşürüyor, ancak yerini almak için yeni Temel Değer Türlerinden birinin mevcut olduğu durumlarda, eski referans türü ("NS" adını koruyarak) etrafta kalır, böylece yine de kullanabilirsiniz. referans semantiğine veya alt sınıflara ihtiyacınız var. Teklife bakın .
rickster

Açıklığa kavuşturmama izin verin: Hatalar gibi bildirim adlarının numaralandırılmasını bekliyorum. Kendi Hata numaralandırmalarınızı tanımlayabilir ve bunları Hata Türü ile uyumlu hale getirebilirsiniz.
hexdreamer

1
Doğru - Apple en azından teorik olarak NotoficationName'i (veya bazılarını) uyumlu tipler oluşturduğunuz bir protokol haline getirebilirdi. Bilmiyorum, ama yapmamalarının bir nedeni var ... Muhtemelen ObjC köprüleme ile bir ilgisi var mı? Daha iyi bir çözüm bulmuşsanız, bir hata bildirin ( açık kaynak için , Foundation Swift açıkta).
rickster

2
Küçük harfle başlaması gerektiği konusunda muhtemelen haklısınız.
hexdreamer

13

Daha kolay yol:

let name:NSNotification.Name = NSNotification.Name("notificationName")
NotificationCenter.default.post(name: name, object: nil)

11

NSNotification.Name'e özel bir başlatıcı ekleyebilirsiniz.

extension NSNotification.Name {
    enum Notifications: String {
        case foo, bar
    }
    init(_ value: Notifications) {
        self = NSNotification.Name(value.rawValue)
    }
}

Kullanımı:

NotificationCenter.default.post(name: Notification.Name(.foo), object: nil)

1
Swift 3.0.2 için küçük harfli 'enum type' ve 'init (_ type: type)'
Jalakoo

@Jalakoo Sıralamanın casekendisi değil, yalnızca bir numaralandırmadaki s'ler küçük harfle yazılmalıdır. Tür adları büyük harfle yazılır ve numaralandırmalar türlerdir.
manmal

9

@CesarVarela'nın önerdiğine benzer başka bir seçenek önerebilirim.

extension Notification.Name {
    static var notificationName: Notification.Name {
        return .init("notificationName")
    }
}

Bu, bildirimleri kolayca yayınlamanıza ve abone olmanıza olanak tanır.

NotificationCenter.default.post(Notification(name: .notificationName))

Umarım bu sana yardımcı olur.


4

Her şeyi oradan oraya karıştırarak kendi uygulamamı yaptım ve bunu en uygun olarak buldum. Kimin ilgisini çekebileceğini paylaşmak:

public extension Notification {
    public class MyApp {
        public static let Something = Notification.Name("Notification.MyApp.Something")
    }
}

class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        NotificationCenter.default.addObserver(self,
                                               selector: #selector(self.onSomethingChange(notification:)),
                                               name: Notification.MyApp.Something,
                                               object: nil)
    }

    deinit {
        NotificationCenter.default.removeObserver(self)
    }

    @IBAction func btnTapped(_ sender: UIButton) {
        NotificationCenter.default.post(name: Notification.MyApp.Something,
                                      object: self,
                                    userInfo: [Notification.MyApp.Something:"foo"])
    }

    func onSomethingChange(notification:NSNotification) {
        print("notification received")
        let userInfo = notification.userInfo!
        let key = Notification.MyApp.Something 
        let something = userInfo[key]! as! String //Yes, this works :)
        print(something)
    }
}


2

Bu sadece referans

// Add observer:
NotificationCenter.default.addObserver(self,
    selector: #selector(notificationCallback),
    name: MyClass.myNotification,
    object: nil)

    // Post notification:
    let userInfo = ["foo": 1, "bar": "baz"] as [String: Any]
    NotificationCenter.default.post(name: MyClass.myNotification,
        object: nil,
        userInfo: userInfo)

1

Numaralandırmanın avantajı, derleyicinin adın doğru olup olmadığını kontrol etmesini sağlamamızdır. Olası sorunları azaltır ve yeniden düzenlemeyi kolaylaştırır.

Bildirim adları için alıntılanmış dizeler yerine numaralandırmaları kullanmayı sevenler için bu kod hile yapar:

enum MyNotification: String {
    case somethingHappened
    case somethingElseHappened
    case anotherNotification
    case oneMore
}

extension NotificationCenter {
    func add(observer: Any, selector: Selector, 
             notification: MyNotification, object: Any? = nil) {
        addObserver(observer, selector: selector, 
                    name: Notification.Name(notification.rawValue),
                    object: object)
    }
    func post(notification: MyNotification, 
              object: Any? = nil, userInfo: [AnyHashable: Any]? = nil) {
        post(name: NSNotification.Name(rawValue: notification.rawValue), 
             object: object, userInfo: userInfo)
    }
}

O zaman bunu şu şekilde kullanabilirsiniz:

NotificationCenter.default.post(.somethingHappened)

Soruyla alakasız olsa da, alıntılanan dizeleri yazmaktan kaçınmak için aynı şey film şeridi bölümleri için de yapılabilir:

enum StoryboardSegue: String {
    case toHere
    case toThere
    case unwindToX
}

extension UIViewController {
    func perform(segue: StoryboardSegue) {
        performSegue(withIdentifier: segue.rawValue, sender: self)
    }
}

Ardından, görünüm denetleyicinizde şöyle adlandırın:

perform(segue: .unwindToX)

> NotificationCenter.default.post(.somethingHappened)Bu bir hata verir; uzantınıza eklediğiniz yöntemler daha fazla argüman kabul eder.

0

Yalnızca dizeli özel bildirimler kullanırsanız, herhangi bir sınıfı genişletmeniz gerekmez, ancak String

    extension String {
        var notificationName : Notification.Name{
            return Notification.Name.init(self)
        }
    }

0

@ CesarVarela'nın yanıtı iyidir, ancak kodu biraz daha temiz hale getirmek için aşağıdakileri yapabilirsiniz:

extension Notification.Name {
    typealias Name = Notification.Name

    static let onSelectedSkin = Name("on-selected-skin")
    static let onFoo = Name("on-foo")
}

0

Aynı anda hem Objective-C hem de Swift kullanan bir projede bunun temiz çalışmasını istiyorsanız, Objective-C'de bildirim oluşturmanın daha kolay olduğunu buldum.

Bir .m / .h dosyası oluşturun:

//CustomNotifications.h
#import <Foundation/Foundation.h>

// Add all notifications here
extern const NSNotificationName yourNotificationName;
//CustomNotifications.m
#import "CustomNotifications.h"

// Add their string values here
const NSNotificationName yourNotificationName = @"your_notification_as_string";

MyProject-Bridging-Header.hOnları Swift'e ifşa etmek için (projenizin adını taşıyan).

#import "CustomNotifications.h"

Bildirimlerinizi Objective-C'de şu şekilde kullanın:

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(yourMethod:) name:yourNotificationName:nil];

Ve Swift'de (5) şöyle:

NotificationCenter.default.addObserver(self, selector: #selector(yourMethod(sender:)), name: .yourNotificationName, object: nil)
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.