Trong Objective-C, một thông báo tùy chỉnh chỉ là một NSString đơn giản, nhưng nó không rõ ràng trong phiên bản WWDC của Swift 3.
Trong Objective-C, một thông báo tùy chỉnh chỉ là một NSString đơn giản, nhưng nó không rõ ràng trong phiên bản WWDC của Swift 3.
Câu trả lời:
Bạn cũng có thể sử dụng một giao thức cho việc này
protocol NotificationName {
var name: Notification.Name { get }
}
extension RawRepresentable where RawValue == String, Self: NotificationName {
var name: Notification.Name {
get {
return Notification.Name(self.rawValue)
}
}
}
Và sau đó xác định tên thông báo của bạn ở enum
bất kỳ đâu bạn muốn. Ví dụ:
class MyClass {
enum Notifications: String, NotificationName {
case myNotification
}
}
Và sử dụng nó như
NotificationCenter.default.post(name: Notifications.myNotification.name, object: nil)
Bằng cách này, tên thông báo sẽ được tách khỏi Tổ chức Notification.Name
. Và bạn sẽ chỉ phải sửa đổi giao thức của mình trong trường hợp triển khai Notification.Name
thay đổi.
NotificationName
thuộc name
tính chỉ được thêm vào các enums tuân theo giao thức.
extension NotificationName where Self: RawRepresentable, Self.RawValue == String {
Có một cách (tôi nghĩ) sạch hơn để đạt được nó
extension Notification.Name {
static let onSelectedSkin = Notification.Name("on-selected-skin")
}
Và sau đó bạn có thể sử dụng nó như thế này
NotificationCenter.default.post(name: .onSelectedSkin, object: selectedSkin)
extension NSNotification.Name
thay vì extension Notification.Name
. Nếu không Swift 3 khiếu nại với'Notification' is ambiguous for type lookup in this context
Notification.post được định nghĩa là:
public func post(name aName: NSNotification.Name, object anObject: AnyObject?)
Trong Objective-C, tên thông báo là một NSString đơn giản. Trong Swift, nó được định nghĩa là NSNotification.Name.
NSNotification.Name được định nghĩa là:
public struct Name : RawRepresentable, Equatable, Hashable, Comparable {
public init(_ rawValue: String)
public init(rawValue: String)
}
Điều này hơi kỳ lạ, vì tôi mong đợi nó là một Enum chứ không phải một cấu trúc tùy chỉnh nào đó dường như không còn lợi ích nữa.
Có một kiểu chữ trong Thông báo cho NSNotification.Name:
public typealias Name = NSNotification.Name
Phần khó hiểu là cả Notification và NSNotification đều tồn tại trong Swift
Vì vậy, để xác định thông báo tùy chỉnh của riêng bạn, hãy thực hiện một số cách như:
public class MyClass {
static let myNotification = Notification.Name("myNotification")
}
Sau đó, để gọi nó:
NotificationCenter.default().post(name: MyClass.myNotification, object: self)
Notification.Name
là một enum, không ai có thể xác định các thông báo mới. Chúng tôi sử dụng cấu trúc cho các kiểu khác giống như enum cần cho phép thêm thành viên mới. (Xem đề xuất phát triển nhanh chóng .)
Notification
là một kiểu giá trị (một cấu trúc), vì vậy nó có thể được hưởng lợi từ ngữ nghĩa của Swift cho khả năng thay đổi giá trị (im). Nói chung, các loại Nền tảng đang loại bỏ "NS" của chúng trong Swift 3, nhưng khi một trong các Loại Giá trị Nền tảng mới tồn tại để thay thế nó, thì loại tham chiếu cũ vẫn tồn tại (giữ tên "NS") để bạn vẫn có thể sử dụng nó khi bạn cần ngữ nghĩa tham chiếu hoặc phân lớp nó. Xem đề xuất .
Cách dễ dàng hơn:
let name:NSNotification.Name = NSNotification.Name("notificationName")
NotificationCenter.default.post(name: name, object: nil)
Bạn có thể thêm trình khởi tạo tùy chỉnh vào NSNotification.Name
extension NSNotification.Name {
enum Notifications: String {
case foo, bar
}
init(_ value: Notifications) {
self = NSNotification.Name(value.rawValue)
}
}
Sử dụng:
NotificationCenter.default.post(name: Notification.Name(.foo), object: nil)
case
s trong enum mới được viết thường, không phải là enum. Tên loại được viết hoa và enum là loại.
Tôi có thể đề xuất một tùy chọn khác tương tự như những gì @CesarVarela đã đề xuất.
extension Notification.Name {
static var notificationName: Notification.Name {
return .init("notificationName")
}
}
Điều này sẽ cho phép bạn đăng và đăng ký thông báo một cách dễ dàng.
NotificationCenter.default.post(Notification(name: .notificationName))
Hy vọng điều này sẽ giúp bạn.
Tôi đã thực hiện việc thực hiện của riêng mình trộn mọi thứ từ đó và ở đó, và thấy điều này là thuận tiện nhất. Chia sẻ cho những ai có thể quan tâm:
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")
Đây chỉ là tham khảo
// 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)
Ưu điểm của việc sử dụng enums là chúng tôi nhận được trình biên dịch để kiểm tra xem tên có đúng không. Giảm các vấn đề tiềm ẩn và giúp tái cấu trúc dễ dàng hơn.
Đối với những người thích sử dụng enums thay vì các chuỗi được trích dẫn cho tên thông báo, mã này thực hiện thủ thuật:
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)
}
}
Sau đó, bạn có thể sử dụng nó như thế này:
NotificationCenter.default.post(.somethingHappened)
Mặc dù không liên quan đến câu hỏi, điều này cũng có thể được thực hiện với các segues bảng phân cảnh, để tránh nhập các chuỗi được trích dẫn:
enum StoryboardSegue: String {
case toHere
case toThere
case unwindToX
}
extension UIViewController {
func perform(segue: StoryboardSegue) {
performSegue(withIdentifier: segue.rawValue, sender: self)
}
}
Sau đó, trên bộ điều khiển chế độ xem của bạn, hãy gọi nó như sau:
perform(segue: .unwindToX)
nếu bạn sử dụng thông báo tùy chỉnh chỉ chuỗi, không có lý do gì để mở rộng bất kỳ lớp nào nhưng String
extension String {
var notificationName : Notification.Name{
return Notification.Name.init(self)
}
}
Nếu bạn muốn điều này hoạt động rõ ràng trong một dự án sử dụng cả Objective-C và Swift cùng một lúc, tôi thấy việc tạo thông báo trong Objective-C sẽ dễ dàng hơn.
Tạo tệp .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";
Trong của bạn MyProject-Bridging-Header.h
(được đặt tên theo dự án của bạn) để cho chúng tiếp xúc với Swift.
#import "CustomNotifications.h"
Sử dụng các thông báo của bạn trong Objective-C như sau:
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(yourMethod:) name:yourNotificationName:nil];
Và trong Swift (5) như thế này:
NotificationCenter.default.addObserver(self, selector: #selector(yourMethod(sender:)), name: .yourNotificationName, object: nil)