Swift의 NSNotificationCenter addObserver


392

Swift에서 옵저버를 기본 알림 센터에 어떻게 추가합니까? 배터리 잔량이 변경되면 알림을 보내는이 코드 줄을 이식하려고합니다.

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(batteryLevelChanged:) name:UIDeviceBatteryLevelDidChangeNotification object:nil];

구체적으로 무엇을 요구하고 있습니까? 선택기가 어떻게 작동합니까?
nschum 2016 년

1
"선택기"유형은 Swift의 문자열이라는 것을 알지 못했습니다. 문서에는 언급이 없습니다.
Berry Blue

답변:


442

Objective-C API와 동일하지만 Swift의 구문을 사용합니다.

스위프트 4.2 및 스위프트 5 :

NotificationCenter.default.addObserver(
    self,
    selector: #selector(self.batteryLevelChanged),
    name: UIDevice.batteryLevelDidChangeNotification,
    object: nil)

관찰자가 Objective-C 오브젝트에서 상속하지 않는 경우 메소드를 @objc선택 자로 사용하려면 메소드 접 두부 를 사용해야합니다.

@objc private func batteryLevelChanged(notification: NSNotification){     
    //do stuff using the userInfo property of the notification object
}

참조 NSNotificationCenter 클래스 참조를 , 오브젝티브 C API와 상호 작용


3
감사! Swift에서 선택기 이름을 전달하는 방법을 몰랐습니다.
Berry Blue

14
@ Bererry, 위의 솔루션이 효과가 있었습니까? 함수가 NSNotification을 매개 변수로 승인하는 경우 "batteryLevelChanged"를 "batteryLevelChanged :"로 변경해야한다고 생각합니다.
Olshansk

1
@Olshansk 네, 맞습니다. 당신은 그것을 필요로합니다. 감사!
Berry Blue

UIDeviceBatteryLevelDidChangeNotification따옴표가 없습니까? 문자열 타입입니다.
kmiklas

13
로 클래스 또는 대상 메소드에 주석을 달아야합니다 @objc.
Klaas

757

스위프트 4.0 및 Xcode 9.0+ :

발송 (포스트) 알림 :

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

또는

NotificationCenter.default.post(name: Notification.Name("NotificationIdentifier"), object: nil, userInfo: ["Renish":"Dadhaniya"])

알림 받기 :

NotificationCenter.default.addObserver(self, selector: #selector(self.methodOfReceivedNotification(notification:)), name: Notification.Name("NotificationIdentifier"), object: nil)

수신 된 알림에 대한 함수 메소드 핸들러 :

@objc func methodOfReceivedNotification(notification: Notification) {}

스위프트 3.0 및 Xcode 8.0 이상 :

발송 (포스트) 알림 :

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

알림 받기 :

NotificationCenter.default.addObserver(self, selector: #selector(YourClassName.methodOfReceivedNotification(notification:)), name: Notification.Name("NotificationIdentifier"), object: nil)

수신 된 알림에 대한 메소드 핸들러 :

func methodOfReceivedNotification(notification: Notification) {
  // Take Action on Notification
}

알림 제거 :

deinit {
  NotificationCenter.default.removeObserver(self, name: Notification.Name("NotificationIdentifier"), object: nil)
}

스위프트 2.3 및 Xcode 7 :

발송 (포스트) 알림

NSNotificationCenter.defaultCenter().postNotificationName("NotificationIdentifier", object: nil)

알림 받기 (받기)

NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(YourClassName.methodOfReceivedNotification(_:)), name:"NotificationIdentifier", object: nil)

수신 된 알림에 대한 메소드 핸들러

func methodOfReceivedNotification(notification: NSNotification){
  // Take Action on Notification
}


역사적인 Xcode 버전의 경우 ...



발송 (포스트) 알림

NSNotificationCenter.defaultCenter().postNotificationName("NotificationIdentifier", object: nil)

알림 받기 (받기)

NSNotificationCenter.defaultCenter().addObserver(self, selector: "methodOfReceivedNotification:", name:"NotificationIdentifier", object: nil)

알림 제거

NSNotificationCenter.defaultCenter().removeObserver(self, name: "NotificationIdentifier", object: nil)
NSNotificationCenter.defaultCenter().removeObserver(self) // Remove from all notifications being observed

수신 된 알림에 대한 메소드 핸들러

func methodOfReceivedNotification(notification: NSNotification) {
  // Take Action on Notification
}

@objc로 클래스 또는 대상 메소드에 주석을 답니다.

@objc private func methodOfReceivedNotification(notification: NSNotification) {
  // Take Action on Notification
}

// Or

dynamic private func methodOfReceivedNotification(notification: NSNotification) {
  // Take Action on Notification
}

21
로 클래스 또는 대상 메소드에 주석을 달아야합니다 @objc.
Klaas

1
@goofansu 확실합니까? 순수한 Swift 클래스 일 때 추가해야한다고 생각합니다.
Klaas

10
methodOFReceivedNoticationdynamicNSObject의 서브 클래스로 주석을 달거나 구성원 이어야합니다 .
Klaas

1
그렇지 않은 경우 런타임 경고가 표시됩니다 object 0x7fd68852d710 of class 'TestNotifications.MyObject' does not implement methodSignatureForSelector: -- trouble ahead.Unrecognized selector -[TestNotifications.MyObject methodOFReceivedNotication:]
Klaas

2
@TaylorAllred, 내 답변을 검토해 주셔서 감사합니다. 나는 당신의 제안에 정말 감사합니다. 나는 그것을 바꿨다. 그것을 검토하십시오.
Dadhaniya

46

이 작업을 수행하는 좋은 방법은 Objective-C 코드에서 자주 사용되는 방법이 addObserver(forName:object:queue:using:)아닌 방법 을 사용하는 것 addObserver(_:selector:name:object:)입니다. 첫 번째 변형의 장점은 @objc메소드 에서 속성 을 사용할 필요가 없다는 것입니다 .

    func batteryLevelChanged(notification: Notification) {
        // do something useful with this information
    }

    let observer = NotificationCenter.default.addObserver(
        forName: NSNotification.Name.UIDeviceBatteryLevelDidChange,
        object: nil, queue: nil,
        using: batteryLevelChanged)

원하는 경우 메소드 대신 클로저를 사용할 수도 있습니다.

    let observer = NotificationCenter.default.addObserver(
        forName: NSNotification.Name.UIDeviceBatteryLevelDidChange,
        object: nil, queue: nil) { _ in print("🔋") }

반환 된 값을 사용하여 나중에 알림 수신을 중지 할 수 있습니다.

    NotificationCenter.default.removeObserver(observer)

이 방법을 사용할 때 또 다른 이점이 있었는데, 이는 컴파일러가 정적으로 확인할 수없는 선택기 문자열을 사용할 필요가 없으므로 메소드의 이름이 바뀌면 깨지기 쉽지 않습니다. 그러나 Swift 2.2 및 나중에 해당 문제를 해결하는 #selector표현식 이 포함됩니다 .


7
대단해! 완전성을 위해 등록 취소 예제도보고 싶습니다. addObserver(_:selector:name:object:) 등록 해제 방법과 는 상당히 다릅니다 . 당신은에 의해 반환 된 개체를 유지해야 addObserverForName(_:object:queue:usingBlock:)하고에 전달removeObserver:
루카스 Goossen은

1
이 (가) 반환 한 객체의 등록 해제를 포함하도록 업데이트해야합니다 addObserverForName(_:object:queue:usingBlock:).
Hyperbole

3
이것은 Obj-C #selector 메소드를 사용해야하기 때문에 connor 또는 Renish (이 의견에서 위의 두 가지)보다 훨씬 더 나은 대답입니다. 그 결과 훨씬 더 신속하고 정확합니다. IMO. 감사!
patr1ck

2
이에서를 사용하는 경우, 말, A, 기억 UIViewController및 참조 self그 폐쇄, 당신은 사용할 필요 [weak self]하거나 참조주기 및 메모리 누수를해야합니다.
Rob N

40

Xcode 8의 스위프트 3.0

Swift 3.0은 structNotificationCenter와 마찬가지로 많은 "문자열 유형"API를 "래퍼 유형"으로 대체했습니다 . 알림은 이제가 struct Notfication.Name아닌로 식별 됩니다 String. Swift 3로 마이그레이션 안내서를 참조하십시오. .

이전 사용법 :

// Define identifier
let notificationIdentifier: String = "NotificationIdentifier"

// Register to receive notification
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(YourClassName.methodOfReceivedNotification(_:)), name: notificationIdentifier, object: nil)

// Post a notification
NSNotificationCenter.defaultCenter().postNotificationName(notificationIdentifier, object: nil)

새로운 Swift 3.0 사용법 :

// Define identifier
let notificationName = Notification.Name("NotificationIdentifier")

// Register to receive notification
NotificationCenter.default.addObserver(self, selector: #selector(YourClassName.methodOfReceivedNotification), name: notificationName, object: nil)

// Post notification
NotificationCenter.default.post(name: notificationName, object: nil)

모든 시스템 알림 유형은 이제 정적 상수로 정의됩니다 Notification.Name. 즉 .UIDeviceBatteryLevelDidChange, .UIApplicationDidFinishLaunching,.UITextFieldTextDidChange , 등

Notification.Name시스템 알림과 일관성을 유지하기 위해 고유 한 사용자 지정 알림으로 확장 할 수 있습니다 .

// Definition:
extension Notification.Name {
    static let yourCustomNotificationName = Notification.Name("yourCustomNotificationName")
}

// Usage:
NotificationCenter.default.post(name: .yourCustomNotificationName, object: nil)

24
  1. 알림 이름 선언

    extension Notification.Name {
        static let purchaseDidFinish = Notification.Name("purchaseDidFinish")
    }
  2. 두 가지 방법으로 관찰자를 추가 할 수 있습니다.

    사용 Selector

    NotificationCenter.default.addObserver(self, selector: #selector(myFunction), name: .purchaseDidFinish, object: nil)
    
    @objc func myFunction(notification: Notification) {
        print(notification.object ?? "") //myObject
        print(notification.userInfo ?? "") //[AnyHashable("key"): "Value"]
    }

    또는 사용 block

    NotificationCenter.default.addObserver(forName: .purchaseDidFinish, object: nil, queue: nil) { [weak self] (notification) in
        guard let strongSelf = self else {
            return
        }
    
        strongSelf.myFunction(notification: notification)
    }
    
    func myFunction(notification: Notification) {
        print(notification.object ?? "") //myObject
        print(notification.userInfo ?? "") //[AnyHashable("key"): "Value"]
    }
  3. 알림 게시

    NotificationCenter.default.post(name: .purchaseDidFinish, object: "myObject", userInfo: ["key": "Value"])

iOS 9 및 OS X 10.11에서. 더 이상 NSNotificationCenter 옵저버가 할당 해제 될 때 자체 등록을 해제 할 필요가 없습니다.더 많은 정보

A의 block기반 구현을 사용하려는 경우 약한 강한 춤을 할 필요가self 블록 내에서. 더 많은 정보

블록 기반 관찰자는 더 많은 정보를 제거해야합니다.

let center = NSNotificationCenter.defaultCenter()
center.removeObserver(self.localeChangeObserver)

5
"iOS 9 및 OS X 10.11부터. 더 이상 NSNotificationCenter 옵저버가 할당 해제 될 때 자체 등록을 해제 할 필요가 없습니다." 이것은 선택기 기반 관찰자에게만 해당됩니다. 블록 기반 옵저버는 여전히 제거해야합니다.
Abhinav

8

NSNotificationCenter를 사용하여 데이터 전달

swift 3.0에서는 NotificationCentre를 사용하고 swift 2.0에서는 NSNotificationCenter를 사용하여 데이터를 전달할 수도 있습니다.

스위프트 2.0 버전

[NSObject : AnyObject] 유형의 선택적인 사전 인 userInfo를 사용하여 정보를 전달 하시겠습니까?

let imageDataDict:[String: UIImage] = ["image": image]

// Post a notification
 NSNotificationCenter.defaultCenter().postNotificationName(notificationName, object: nil, userInfo: imageDataDict)

// Register to receive notification in your class
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(self.showSpinningWheel(_:)), name: notificationName, object: nil)

// handle notification
func showSpinningWheel(notification: NSNotification) {
  if let image = notification.userInfo?["image"] as? UIImage {
  // do something with your image   
  }
}

스위프트 3.0 버전

userInfo는 이제 [AnyHashable : Any]? Swift에서 사전 리터럴로 제공하는 인수로

let imageDataDict:[String: UIImage] = ["image": image]

// post a notification
 NotificationCenter.default.post(name: NSNotification.Name(rawValue: "notificationName"), object: nil, userInfo: imageDataDict) 
// `default` is now a property, not a method call

// Register to receive notification in your class
NotificationCenter.default.addObserver(self, selector: #selector(self.showSpinningWheel(_:)), name: NSNotification.Name(rawValue: "notificationName"), object: nil)

// handle notification
func showSpinningWheel(_ notification: NSNotification) {

  if let image = notification.userInfo?["image"] as? UIImage {
  // do something with your image   
  }
}

NotificationCentre (swift 3.0) 및 NSNotificationCenter (swift 2.0)를 사용한 소스 패스 데이터


도움이되었다 니 다행입니다 :)
Sahil

6

에서 스위프트 (5)

ViewControllerB에서 ViewControllerA로 데이터를 수신하려면

ViewControllerA (수신기)

import UIKit

class ViewControllerA: UIViewController  {

    override func viewDidLoad() {
        super.viewDidLoad()

        //MARK: - - - - - Code for Passing Data through Notification Observer - - - - -
        // add observer in controller(s) where you want to receive data
        NotificationCenter.default.addObserver(self, selector: #selector(self.methodOfReceivedNotification(notification:)), name: Notification.Name("NotificationIdentifier"), object: nil)
    }

    //MARK: - - - - - Method for receiving Data through Post Notificaiton - - - - -
    @objc func methodOfReceivedNotification(notification: Notification) {
        print("Value of notification : ", notification.object ?? "")
    }
}

ViewControllerB (발신자)

import UIKit

class ViewControllerB: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        //MARK: - - - - - Set data for Passing Data Post Notification - - - - -
        let objToBeSent = "Test Message from Notification"
        NotificationCenter.default.post(name: Notification.Name("NotificationIdentifier"), object: objToBeSent)
    }

}

2

@objc로 주석을 달지 않고 선택기를 성공적으로 사용하기 위해 다음 중 하나를 수행 할 수 있습니다 .

NSNotificationCenter.defaultCenter().addObserver(self,
    selector:"batteryLevelChanged:" as Selector,
    name:"UIDeviceBatteryLevelDidChangeNotification",
    object:nil)    

또는

let notificationSelector: Selector = "batteryLevelChanged:"

NSNotificationCenter.defaultCenter().addObserver(self,
    selector: notificationSelector,
    name:"UIDeviceBatteryLevelDidChangeNotification",
    object:nil)    

내 xcrun 버전은 Swift 1.2를 보여 주며 Xcode 6.4 및 Xcode 7 베타 2에서 작동합니다 (Swift 2.0을 사용한다고 생각했습니다).

$xcrun swift --version

Apple Swift version 1.2 (swiftlang-602.0.53.1 clang-602.0.53)

@objc옵저버 클래스가에서 상속받은 경우 주석을 달지 않아도됩니다 NSObject.
Antonio Favata

명시 적으로 캐스팅에 그리고 당신은 필요가 없습니다 StringSelector중. :)
Antonio Favata

@ alfvata : 내 관찰자 클래스가 NSObject에서 상속되지 않습니다. Swift 스타일의 AnyObject에서 상속합니다. 명시 적으로 문자열을 Selector로 캐스팅하면 다른 Objective-C 관련 해결 방법을 피할 수 있습니다.
leanne

그것이 어떻게 작동하는지 잘 모르겠습니다. 관찰자가 @objc아닌 NSObject클래스 의 메서드에서 주석을 제거하고 선택기 이름에 as Selector캐스팅을 추가 String했으며 알림이 실행될 때 앱이 중단됩니다. 내 Swift 버전은 귀하의 버전과 동일합니다.
안토니오 Favata

3
@alfavata, 나는 당신에게 무엇을 말 해야할지 모르겠습니다. 나는 현재 Xcode Beta 4를 사용하고 있으며 여전히 작동 중입니다. 내 프로젝트는 완전히 스위프트입니다. Objective-C 구성 요소가 없습니다. 어쩌면 그것은 차이가 있습니다. 프로젝트 설정에 다른 것이있을 수 있습니다. 여러 가지 가능성이 있습니다! 나는 말할 것입니다 : @objc주석이 당신을 위해 효과가 있고이 방법으로는 효과가 없다면, 계속 주석을 달아주세요!
leanne

2

빠른 2.2 - 엑스 코드 7.3, 우리는 사용 #selector을 위해NSNotificationCenter

 NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(rotate), name: UIDeviceOrientationDidChangeNotification, object: nil)

2

알림도 제거해야합니다.

전의.

deinit 
{
  NotificationCenter.default.removeObserver(self, name:NSNotification.Name(rawValue: "notify"), object: nil)

}

2
iOS 9부터는 필요하지 않다고 생각합니다. 자동으로 완료됩니다.
빅토르 쿠 케라

1

Swift 3, Xcode 8.2에서 : 배터리 상태 확인

//Add observer
NotificationCenter.default.addObserver(self, selector: #selector(batteryStateDidChange), name: NSNotification.Name.UIDeviceBatteryStateDidChange, object: nil)


 //Fired when battery level changes

 func batteryStateDidChange(notification: NSNotification){
        //perform manipulation here
    }

1

NSNotificationCenter , iOS 11 용 Swift 4.0 에서 옵저버 구문 추가

  NotificationCenter.default.addObserver(self, selector: #selector(keyboardShow), name: NSNotification.Name.UIKeyboardWillShow, object: nil)

이것은 keyboardWillShow 알림 이름 유형입니다. 사용 가능한 옵션에서 다른 유형을 선택할 수 있습니다

선택기는 @objc func 유형이며 키보드 표시 방법을 처리합니다 (이것은 사용자 기능입니다)


이 답변을 읽는 사람에게 명확히하기 위해 : "Selector is type @objc func ..."는 관련 함수에 #selector주석을 달아야 함을 의미합니다 @objc. 예를 들어 @objc func keyboardShow() { ... }, Swift 4에서 잠시 동안 나를 던졌습니다!
leanne

0

스위프트 5 및 Xcode 10.2 :

NotificationCenter.default.addObserver(
            self,
            selector: #selector(batteryLevelDidChangeNotification),
            name: UIDevice.batteryLevelDidChangeNotification,
            object: nil)

0

스위프트 5 알림 관찰자

override func viewDidLoad() {
    super.viewDidLoad() 
    NotificationCenter.default.addObserver(self, selector: #selector(batteryLevelChanged), name: UIDevice.batteryLevelDidChangeNotification, object: nil)
}

@objc func batteryLevelChanged(notification : NSNotification){
    //do here code
}

override func viewWillDisappear(_ animated: Bool) {
    NotificationCenter.default.removeObserver(self, name: UIDevice.batteryLevelDidChangeNotification, object: nil)

}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.