Objective-Cでは、カスタム通知は単純なNSStringですが、Swift 3のWWDCバージョンでは、それが何であるかが明確ではありません。
Objective-Cでは、カスタム通知は単純なNSStringですが、Swift 3のWWDCバージョンでは、それが何であるかが明確ではありません。
回答:
このためのプロトコルを使用することもできます
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
変更された場合にのみ、プロトコルを変更する必要があります。
NotificationName
できるように、コードを編集して拡張機能のname
準拠を追加しました。
extension NotificationName where Self: RawRepresentable, Self.RawValue == String {
それを達成するためのよりクリーンな(私は思う)方法があります
extension Notification.Name {
static let onSelectedSkin = Notification.Name("on-selected-skin")
}
そして、あなたはこのようにそれを使うことができます
NotificationCenter.default.post(name: .onSelectedSkin, object: selectedSkin)
extension NSNotification.Name
の代わりにextension Notification.Name
。それ以外の場合のSwift 3の苦情'Notification' is ambiguous for type lookup in this context
Notification.postは次のように定義されます。
public func post(name aName: NSNotification.Name, object anObject: AnyObject?)
Objective-Cでは、通知名はプレーンなNSStringです。Swiftでは、NSNotification.Nameとして定義されています。
NSNotification.Nameは次のように定義されます。
public struct Name : RawRepresentable, Equatable, Hashable, Comparable {
public init(_ rawValue: String)
public init(rawValue: String)
}
私はそれがEnumであり、利点がないように見えるいくつかのカスタム構造体ではないので、これは奇妙なことです。
NSNotification.Nameの通知にはタイプエイリアスがあります。
public typealias Name = NSNotification.Name
混乱する部分は、通知とNSNotificationの両方がSwiftに存在することです
したがって、独自のカスタム通知を定義するには、次のようにします。
public class MyClass {
static let myNotification = Notification.Name("myNotification")
}
それを呼び出すには:
NotificationCenter.default().post(name: MyClass.myNotification, object: self)
より簡単な方法:
let name:NSNotification.Name = NSNotification.Name("notificationName")
NotificationCenter.default.post(name: name, object: nil)
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)
case
enum自体ではなく、enum内のs のみを小文字にする必要があります。タイプ名は大文字で、列挙型はタイプです。
私はあちこちで物事を混ぜて自分の実装を行い、これが最も便利だと思いました。興味のある人のために共有する:
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)
}
}
これは参考です
// 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)
enumを使用する利点は、名前が正しいことをコンパイラーにチェックさせることです。潜在的な問題を減らし、リファクタリングを容易にします。
通知名に引用符付き文字列の代わりに列挙型を使用したい人のために、このコードはトリックを行います:
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)
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
(プロジェクトにちなんで名付けられた)でそれらをSwiftに公開します。
#import "CustomNotifications.h"
次のようにObjective-Cで通知を使用します。
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(yourMethod:) name:yourNotificationName:nil];
そして、Swift(5)では次のようになります。
NotificationCenter.default.addObserver(self, selector: #selector(yourMethod(sender:)), name: .yourNotificationName, object: nil)