Swift 3에서 사용자 지정 알림을 어떻게 생성합니까?


답변:


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.
halil_g

엄격히 동일하지만 더 논리적 IMO입니다. 다음과 같이 NotificationName (RawRepresentable 대신)에 확장을 정의 할 수 있습니다.extension NotificationName where Self: RawRepresentable, Self.RawValue == String {
jlj

387

그것을 달성하는 더 깨끗한 (내 생각에) 방법이 있습니다

extension Notification.Name {

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

그런 다음 이렇게 사용할 수 있습니다

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

2
위의 코드를 사용하고 있습니다. 이것은 정적 속성입니다.
Cesar Varela

3
매우 깨끗하고, 내가 좋아 많이
톰 WOLTERS

10
extension NSNotification.Name 대신 extension Notification.Name . 그렇지 않으면 스위프트 3 불만'Notification' is ambiguous for type lookup in this context
lluisgh

9
당신은 문자열에 오타를 만들어서 입력 된 알림 이름의 값을 보여주기 위해 나의
Dorian Roy

10
이것이 WWDC 2016 세션 (207)에 Apple에서 제안하는 방법입니다 협조 할 수 있습니다 developer.apple.com/videos/play/wwdc2016/207
레온

36

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이 될 것으로 기대하기 때문에 다소 이상합니다.

Notification for NSNotification.Name에는 typealias가 있습니다.

public typealias Name = NSNotification.Name

혼란스러운 부분은 알림과 NSNotification이 모두 Swift에 존재한다는 것입니다.

따라서 고유 한 사용자 지정 알림을 정의하려면 다음과 같이하십시오.

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

그런 다음 그것을 부릅니다.

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

3
좋은 대답입니다. 일부 의견 : 이것은 일종의 이상합니다. Enum이 될 것으로 예상하기 때문 입니다. enum은 닫힌 집합입니다. Notification.Name열거 형 이라면 아무도 새 알림을 정의 할 수 없습니다. 새 멤버를 추가 할 수 있어야하는 열거 형과 같은 형식에 구조체를 사용합니다. ( 빠른 진화 제안을 참조하십시오 .)
rickster

2
혼란 부분은 스위프트 모두 알림 및 NSNotification의 존재가 있다는 것입니다 - Notification값 형식 (구조체)가이 값 (IM) 가변성에 대한 스위프트의 의미 혜택을 누릴 수 있도록한다. 일반적으로 Foundation 유형은 Swift 3에서 "NS"를 삭제하지만이를 대체하기 위해 새로운 Foundation Value 유형 중 하나가 존재하는 경우 이전 참조 유형이 계속 유지되므로 ( "NS"이름 유지) 다음과 같은 경우에도 계속 사용할 수 있습니다. 참조 의미 체계 또는 하위 클래스가 필요합니다. 제안을 참조하십시오 .
rickster

명확히하자 : 알림 이름은 오류처럼 열거 형이 될 것으로 예상합니다. 고유 한 Error 열거 형을 정의하고 ErrorType을 준수하도록 만들 수 있습니다.
hexdreamer

1
사실 — Apple은 이론적으로 적어도 이론적으로 NotoficationName (또는 일부)을 프로토콜로 만들 수 있으며 이에 따라 적합한 유형을 만들 수 있습니다. 몰라요,하지만 그들이하지 않은 이유가있을 것 같습니다 ... 아마도 ObjC 브리징과 관련이 있습니까? 더 나은 솔루션이 해결 된 경우 버그를 제출하십시오 ( 오픈 소스 에 Foundation Swift가 공개 중입니다).
rickster

2
소문자로 시작해야한다는 점에서 아마 정확합니다.
hexdreamer

13

더 쉬운 방법 :

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

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
Swift 3.0.2 용 소문자 'enum type'및 'init (_ type : type)'
Jalakoo

@Jalakoo case열거 형 자체가 아니라 열거 형 의 s 만 소문자 여야합니다. 유형 이름은 대문자이고 열거 형은 유형입니다.
manmal

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)

질문과 관련이 없지만 따옴표로 묶인 문자열을 입력하지 않도록 스토리 보드 segues에서도 동일한 작업을 수행 할 수 있습니다.

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];

그리고 Swift (5)에서는 다음과 같습니다.

NotificationCenter.default.addObserver(self, selector: #selector(yourMethod(sender:)), name: .yourNotificationName, object: nil)
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.