आप स्विफ्ट 3 में कस्टम नोटिफिकेशन कैसे बनाते हैं?


112

ऑब्जेक्टिव-सी में, एक कस्टम नोटिफिकेशन सिर्फ एक सादा NSString है, लेकिन स्विफ्ट 3 के WWDC संस्करण में यह स्पष्ट नहीं है कि यह क्या होना चाहिए।


जवाबों:


32

आप इसके लिए एक प्रोटोकॉल का उपयोग भी कर सकते हैं

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

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

और फिर अपने अधिसूचना नामों को enumकहीं भी आप चाहते हैं के रूप में परिभाषित करें । उदाहरण के लिए:

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

और इसका उपयोग करें

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

इस तरह से फाउंडेशन की ओर से नोटिफिकेशन के नाम डिक्लेय किए जाएंगे Notification.Name। और Notification.Nameपरिवर्तनों के कार्यान्वयन के मामले में आपको केवल अपने प्रोटोकॉल को संशोधित करना होगा ।


यह बिल्कुल वैसा ही है जैसा मैंने सोचा था कि मूल रूप से यह काम करना चाहिए - सूचनाओं का होना चाहिए। चाल के लिए धन्यवाद!
hexdreamer

कोई दिक्कत नहीं है! मैंने विस्तार को शामिल करने के लिए कोड को संपादित किया NotificationNameताकि nameसंपत्ति केवल उन प्रोटोकॉल में जोड़ी जाए जो प्रोटोकॉल के अनुरूप हैं।
हालिल_गैग

कड़ाई से समकक्ष लेकिन अधिक तार्किक IMO, आप नोटिफिकेशननाम पर विस्तार को परिभाषित कर सकते हैं (इसके बजाय RawRepresentable):extension NotificationName where Self: RawRepresentable, Self.RawValue == String {
jlj

388

इसे प्राप्त करने के लिए एक क्लीनर (मुझे लगता है) तरीका है

extension Notification.Name {

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

और फिर आप इसे इस तरह से उपयोग कर सकते हैं

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

2
मैं ऊपर दिए गए कोड का उपयोग कर रहा हूं। यह एक स्थिर संपत्ति है।
सेसर वरेला

3
बहुत साफ, मुझे यह बहुत पसंद है
टॉम वोटर्स

10
extension NSNotification.Name के बजाय extension Notification.Name । अन्यथा स्विफ्ट 3 शिकायतों के साथ'Notification' is ambiguous for type lookup in this context
lluisgh

9
आप स्ट्रिंग में एक टाइपो बनाने के लिए मेरे उत्थान को प्राप्त करते हैं और इस प्रकार टाइप किए गए अधिसूचना नामों के मूल्य का प्रदर्शन करते हैं: पी
डोरियन रॉय

10
यह ध्यान देने योग्य हो सकता है कि यह Apple द्वारा WWDC 2016 सत्र में सुझाया गया है। सत्र 207 डेवलपर.
लियोन

36

अधिसूचना.पोस्ट को इस प्रकार परिभाषित किया गया है:

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

ऑब्जेक्टिव-सी में, अधिसूचना नाम एक सादा एनएसएसटृिंग है। स्विफ्ट में, इसे NSNotification.Name के रूप में परिभाषित किया गया है।

NSNotification.Name के रूप में परिभाषित किया गया है:

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

यह अजीब तरह का है, क्योंकि मैं उम्मीद करता हूं कि यह एक एनम होगा, और कुछ कस्टम संरचना के साथ प्रतीत नहीं होता है और अधिक लाभ।

NSNotification.Name के लिए अधिसूचना में एक टाइपियासिस है:

public typealias Name = NSNotification.Name

भ्रामक हिस्सा यह है कि अधिसूचना और NSNotification दोनों स्विफ्ट में मौजूद हैं

तो अपने स्वयं के कस्टम अधिसूचना को परिभाषित करने के लिए, जैसे किसी दिन करें:

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

फिर इसे कॉल करने के लिए:

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

3
अच्छा उत्तर। कुछ टिप्पणियां: यह अजीब तरह का है, क्योंकि मैं उम्मीद करूंगा कि यह एक एनम है - एनम एक बंद सेट है। यदि Notification.Nameकोई एनम होता, तो कोई भी नई सूचनाओं को परिभाषित करने में सक्षम नहीं होता। हम अन्यथा एनुम-जैसे प्रकारों के लिए संरचनाओं का उपयोग करते हैं जिन्हें नए सदस्यों को जोड़ने की अनुमति देने की आवश्यकता होती है। ( स्विफ्ट-इवोल्यूशन प्रस्ताव देखें ।)
रिकस्टर

2
भ्रामक हिस्सा यह है कि अधिसूचना और NSNotification दोनों स्विफ्ट में मौजूद हैं - Notificationएक मूल्य प्रकार (एक संरचना) है, जिससे कि यह स्विफ्ट के शब्दार्थ से मूल्य (im) के लिए लाभ हो सकता है। आमतौर पर, फाउंडेशन प्रकार स्विफ्ट 3 में अपने "एनएस" को गिरा रहे हैं, लेकिन जहां एक नया फाउंडेशन वैल्यू प्रकार इसे दबाने के लिए मौजूद है, पुराना संदर्भ प्रकार चारों ओर चिपक जाता है ("एनएस" नाम रखते हुए) ताकि आप अभी भी इसका उपयोग कर सकें आपको संदर्भ शब्दार्थ की आवश्यकता है या इसे उप-वर्ग करना है। प्रस्ताव देखें ।
रिकस्टर

मुझे स्पष्ट करने दें: मुझे उम्मीद है कि अधिसूचना के नाम दुश्मनी होंगे, जैसे त्रुटियां हैं। आप अपने स्वयं के त्रुटि एनम को परिभाषित कर सकते हैं, और उन्हें ErrorType के अनुरूप बना सकते हैं।
हेक्सड्रीमर

1
सच है - Apple कम से कम सैद्धांतिक रूप से NotoficationName (या कुछ ऐसे) को एक प्रोटोकॉल बना सकता है, जिससे आप अनुरूप प्रकार बना सकते हैं। मुझे पता नहीं है, लेकिन संभावना है कि वे ऐसा नहीं कर रहे थे ... शायद ओब्जेक ब्रिजिंग के साथ कुछ करना है? एक बग दर्ज करें ( स्रोत को खोलने के लिए , फाउंडेशन स्विफ्ट खुले में है) अगर आपको बेहतर समाधान मिल गया है।
रिकस्टर

2
आप शायद सही हैं कि यह लोअरकेस से शुरू होना चाहिए।
हेक्सड्रीमर


11

आप NSNotification.Name में एक कस्टम इनिशियलाइज़र जोड़ सकते हैं

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

उपयोग:

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

1
लोअर केस 'एनुम टाइप' और '
इनिट

@ जालाकु caseएक एनम में केवल एस को ही उतारा जाना चाहिए, एनम को ही नहीं। टाइप नाम अपरकेस हैं, और एनम टाइप हैं।
मणिमाल

9

मैं एक और विकल्प सुझा सकता हूं जो @CesarVarela के समान है।

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

यह आपको सूचनाओं को आसानी से पोस्ट और सबस्क्राइब करने देगा।

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

आशा है कि यह आपकी मदद करेगा।


4

मैंने अपने कार्यान्वयन को वहां और वहां से चीजों को मिलाकर किया, और इसे सबसे सुविधाजनक पाया। जो कोई भी दिलचस्पी हो सकती है, उसके लिए साझा करना:

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

यह सिर्फ संदर्भ है

// 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

एनम का उपयोग करने का लाभ यह है कि हमें यह जांचने के लिए कंपाइलर मिलता है कि नाम सही है। संभावित मुद्दों को कम करता है और रिफैक्टिंग को आसान बनाता है।

उन लोगों के लिए जो अधिसूचना नामों के लिए उद्धृत स्ट्रिंग्स के बजाय एनम का उपयोग करना पसंद करते हैं, यह कोड चाल करता है:

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)
    }
}

तो आप इसे इस तरह से उपयोग कर सकते हैं:

NotificationCenter.default.post(.somethingHappened)

हालांकि प्रश्न से असंबंधित है, स्टोरीबोर्ड सेग के साथ भी ऐसा ही किया जा सकता है, ताकि उद्धृत तारों से बचा जा सके:

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

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

फिर, अपने व्यू कंट्रोलर पर कॉल करें जैसे:

perform(segue: .unwindToX)

> NotificationCenter.default.post(.somethingHappened)यह एक त्रुटि फेंकता है; आपके द्वारा अपने विस्तार में जोड़े गए तरीके अधिक तर्क स्वीकार करते हैं।

0

यदि आप स्ट्रिंग-केवल कस्टम सूचनाओं का उपयोग करते हैं, तो किसी भी वर्ग को विस्तारित करने का कोई कारण नहीं है लेकिन String

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

0

@ CesarVarela का उत्तर अच्छा है, लेकिन कोड को थोड़ा साफ करने के लिए, आप निम्न कार्य कर सकते हैं:

extension Notification.Name {
    typealias Name = Notification.Name

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

0

यदि आप चाहते हैं कि एक ऐसे प्रोजेक्ट में सफाई से काम किया जाए, जो एक ही समय में Objective-C और Swift दोनों का उपयोग करता है, तो मैंने पाया कि Objective-C में नोटिफिकेशन बनाना आसान है।

एक .m / .h फ़ाइल बनाएँ:

//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.h(अपने प्रोजेक्ट के नाम पर) उन्हें स्विफ्ट के सामने लाने के लिए।

#import "CustomNotifications.h"

इस तरह Objective-C में अपनी सूचनाओं का उपयोग करें:

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

और इस तरह स्विफ्ट (5) में:

NotificationCenter.default.addObserver(self, selector: #selector(yourMethod(sender:)), name: .yourNotificationName, object: nil)
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.