Di Objective-C, pemberitahuan khusus hanyalah NSString biasa, tetapi tidak jelas dalam versi WWDC dari Swift 3 apa yang seharusnya.
Di Objective-C, pemberitahuan khusus hanyalah NSString biasa, tetapi tidak jelas dalam versi WWDC dari Swift 3 apa yang seharusnya.
Jawaban:
Anda juga bisa menggunakan protokol untuk ini
protocol NotificationName {
var name: Notification.Name { get }
}
extension RawRepresentable where RawValue == String, Self: NotificationName {
var name: Notification.Name {
get {
return Notification.Name(self.rawValue)
}
}
}
Dan kemudian tentukan nama notifikasi Anda sebagai enum
mana pun yang Anda inginkan. Sebagai contoh:
class MyClass {
enum Notifications: String, NotificationName {
case myNotification
}
}
Dan gunakan seperti itu
NotificationCenter.default.post(name: Notifications.myNotification.name, object: nil)
Dengan cara ini nama notifikasi akan dipisahkan dari Foundation Notification.Name
. Dan Anda hanya perlu memodifikasi protokol Anda jika ada Notification.Name
perubahan implementasi .
NotificationName
sehingga name
properti hanya ditambahkan ke enum yang sesuai dengan protokol.
extension NotificationName where Self: RawRepresentable, Self.RawValue == String {
Ada cara yang lebih bersih (menurut saya) untuk mencapainya
extension Notification.Name {
static let onSelectedSkin = Notification.Name("on-selected-skin")
}
Dan kemudian Anda bisa menggunakannya seperti ini
NotificationCenter.default.post(name: .onSelectedSkin, object: selectedSkin)
extension NSNotification.Name
bukannya extension Notification.Name
. Jika tidak, Swift 3 mengeluh dengan'Notification' is ambiguous for type lookup in this context
Notification.post didefinisikan sebagai:
public func post(name aName: NSNotification.Name, object anObject: AnyObject?)
Di Objective-C, nama notifikasi adalah NSString biasa. Di Swift, ini didefinisikan sebagai NSNotification.Name.
NSNotification.Name didefinisikan sebagai:
public struct Name : RawRepresentable, Equatable, Hashable, Comparable {
public init(_ rawValue: String)
public init(rawValue: String)
}
Ini agak aneh, karena saya berharap itu menjadi Enum, dan bukan beberapa struct kustom dengan manfaat yang tampaknya tidak lebih.
Ada typealias di Notification for NSNotification.Name:
public typealias Name = NSNotification.Name
Bagian yang membingungkan adalah Notification dan NSNotification ada di Swift
Jadi untuk menentukan notifikasi kustom Anda sendiri, lakukan sesuatu seperti:
public class MyClass {
static let myNotification = Notification.Name("myNotification")
}
Kemudian menyebutnya:
NotificationCenter.default().post(name: MyClass.myNotification, object: self)
Notification.Name
merupakan enum, tidak ada yang dapat menentukan notifikasi baru. Kami menggunakan struct untuk tipe sebaliknya-enum yang perlu mengizinkan penambahan anggota baru. (Lihat proposal evolusi-cepat .)
Notification
merupakan tipe nilai (struct), sehingga dapat memanfaatkan semantik Swift untuk nilai (im) mutabilitas. Umumnya, jenis Fondasi menghilangkan "NS" mereka di Swift 3, tetapi di mana salah satu Jenis Nilai Fondasi baru ada untuk menggantikannya, jenis referensi lama tetap ada (tetap menggunakan nama "NS") sehingga Anda masih dapat menggunakannya saat Anda memerlukan semantik referensi atau untuk membuat subkelasnya. Lihat proposalnya .
Cara yang lebih mudah:
let name:NSNotification.Name = NSNotification.Name("notificationName")
NotificationCenter.default.post(name: name, object: nil)
Anda dapat menambahkan penginisialisasi khusus ke NSNotification.Name
extension NSNotification.Name {
enum Notifications: String {
case foo, bar
}
init(_ value: Notifications) {
self = NSNotification.Name(value.rawValue)
}
}
Pemakaian:
NotificationCenter.default.post(name: Notification.Name(.foo), object: nil)
case
s dalam enum yang harus dikecilkan , bukan enum itu sendiri. Nama tipe diberi huruf besar, dan enum adalah tipe.
Saya mungkin menyarankan opsi lain yang mirip dengan apa yang disarankan @CesarVarela.
extension Notification.Name {
static var notificationName: Notification.Name {
return .init("notificationName")
}
}
Ini akan memungkinkan Anda memposting dan berlangganan pemberitahuan dengan mudah.
NotificationCenter.default.post(Notification(name: .notificationName))
Semoga ini bisa membantu Anda.
Saya melakukan implementasi saya sendiri dengan mencampur berbagai hal dari sana dan di sana, dan menemukan ini sebagai yang paling nyaman. Berbagi untuk siapa saja yang mungkin tertarik:
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)
}
}
NSNotification.Name(rawValue: "myNotificationName")
Ini hanya referensi
// 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)
Keuntungan menggunakan enum adalah kita meminta kompiler untuk memeriksa apakah namanya benar. Mengurangi potensi masalah dan mempermudah pemfaktoran ulang.
Bagi mereka yang suka menggunakan enum daripada kutipan string untuk nama notifikasi, kode ini melakukan triknya:
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)
}
}
Kemudian Anda bisa menggunakannya seperti ini:
NotificationCenter.default.post(.somethingHappened)
Meskipun tidak terkait dengan pertanyaan, hal yang sama dapat dilakukan dengan segmen storyboard, untuk menghindari mengetik string yang dikutip:
enum StoryboardSegue: String {
case toHere
case toThere
case unwindToX
}
extension UIViewController {
func perform(segue: StoryboardSegue) {
performSegue(withIdentifier: segue.rawValue, sender: self)
}
}
Kemudian, pada pengontrol tampilan Anda, sebut seperti:
perform(segue: .unwindToX)
jika Anda menggunakan notifikasi khusus khusus string, tidak ada alasan untuk memperluas kelas apa pun kecuali String
extension String {
var notificationName : Notification.Name{
return Notification.Name.init(self)
}
}
Jika Anda ingin ini bekerja dengan bersih dalam proyek yang menggunakan Objective-C dan Swift pada saat yang sama, menurut saya akan lebih mudah untuk membuat notifikasi di Objective-C.
Buat file .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";
Di Anda MyProject-Bridging-Header.h
(dinamai menurut proyek Anda) untuk mengekspos mereka ke Swift.
#import "CustomNotifications.h"
Gunakan notifikasi Anda di Objective-C seperti ini:
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(yourMethod:) name:yourNotificationName:nil];
Dan di Swift (5) seperti ini:
NotificationCenter.default.addObserver(self, selector: #selector(yourMethod(sender:)), name: .yourNotificationName, object: nil)