| // This source file is part of the Swift.org open source project |
| // |
| // Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors |
| // Licensed under Apache License v2.0 with Runtime Library Exception |
| // |
| // See http://swift.org/LICENSE.txt for license information |
| // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors |
| // |
| |
| public class NSNotification : NSObject, NSCopying, NSCoding { |
| private(set) public var name: String |
| |
| private(set) public var object: AnyObject? |
| |
| private(set) public var userInfo: [NSObject : AnyObject]? |
| |
| public convenience override init() { |
| /* do not invoke; not a valid initializer for this class */ |
| fatalError() |
| } |
| |
| public init(name: String, object: AnyObject?, userInfo: [NSObject : AnyObject]?) { |
| self.name = name |
| self.object = object |
| self.userInfo = userInfo |
| } |
| |
| public convenience required init?(coder aDecoder: NSCoder) { |
| if aDecoder.allowsKeyedCoding { |
| guard let name = aDecoder.decodeObjectOfClass(NSString.self, forKey:"NS.name") else { |
| return nil |
| } |
| let object = aDecoder.decodeObjectForKey("NS.object") |
| let userInfo = aDecoder.decodeObjectOfClass(NSDictionary.self, forKey: "NS.userinfo") |
| self.init(name: name.bridge(), object: object, userInfo: userInfo?.bridge()) |
| } else { |
| guard let name = aDecoder.decodeObject() as? NSString else { |
| return nil |
| } |
| let object = aDecoder.decodeObject() |
| let userInfo = aDecoder.decodeObject() as? NSDictionary |
| self.init(name: name.bridge(), object: object, userInfo: userInfo?.bridge()) |
| } |
| } |
| |
| public func encodeWithCoder(_ aCoder: NSCoder) { |
| if aCoder.allowsKeyedCoding { |
| aCoder.encodeObject(self.name.bridge(), forKey:"NS.name") |
| aCoder.encodeObject(self.object, forKey:"NS.object") |
| aCoder.encodeObject(self.userInfo?.bridge(), forKey:"NS.userinfo") |
| } else { |
| aCoder.encodeObject(self.name.bridge()) |
| aCoder.encodeObject(self.object) |
| aCoder.encodeObject(self.userInfo?.bridge()) |
| } |
| } |
| |
| public override func copy() -> AnyObject { |
| return copyWithZone(nil) |
| } |
| |
| public func copyWithZone(_ zone: NSZone) -> AnyObject { |
| return self |
| } |
| |
| public override var description: String { |
| var str = "\(self.dynamicType) \(unsafeAddress(of: self)) {" |
| |
| str += "name = \(self.name)" |
| if let object = self.object { |
| str += "; object = \(object)" |
| } |
| if let userInfo = self.userInfo { |
| str += "; userInfo = \(userInfo)" |
| } |
| str += "}" |
| |
| return str |
| } |
| } |
| |
| extension NSNotification { |
| public convenience init(name aName: String, object anObject: AnyObject?) { |
| self.init(name: aName, object: anObject, userInfo: nil) |
| } |
| } |
| |
| private class NSNotificationReceiver : NSObject { |
| private weak var object: NSObject? |
| private var name: String? |
| private var block: ((NSNotification) -> Void)? |
| private var sender: AnyObject? |
| } |
| |
| extension Sequence where Iterator.Element : NSNotificationReceiver { |
| |
| /// Returns collection of `NSNotificationReceiver`. |
| /// |
| /// Will return: |
| /// - elements that property `object` is not equal to `observerToFilter` |
| /// - elements that property `name` is not equal to parameter `name` if specified. |
| /// - elements that property `sender` is not equal to parameter `object` if specified. |
| /// |
| private func filterOutObserver(_ observerToFilter: AnyObject, name:String? = nil, object: AnyObject? = nil) -> [Iterator.Element] { |
| return self.filter { observer in |
| |
| let differentObserver = observer.object !== observerToFilter |
| let nameSpecified = name != nil |
| let differentName = observer.name != name |
| let objectSpecified = object != nil |
| let differentSender = observer.sender !== object |
| |
| return differentObserver || (nameSpecified && differentName) || (objectSpecified && differentSender) |
| } |
| } |
| |
| /// Returns collection of `NSNotificationReceiver`. |
| /// |
| /// Will return: |
| /// - elements that property `sender` is `nil` or equals specified parameter `sender`. |
| /// - elements that property `name` is `nil` or equals specified parameter `name`. |
| /// |
| private func observersMatchingName(_ name:String? = nil, sender: AnyObject? = nil) -> [Iterator.Element] { |
| return self.filter { observer in |
| |
| let emptyName = observer.name == nil |
| let sameName = observer.name == name |
| let emptySender = observer.sender == nil |
| let sameSender = observer.sender === sender |
| |
| return (emptySender || sameSender) && (emptyName || sameName) |
| } |
| } |
| } |
| |
| private let _defaultCenter: NSNotificationCenter = NSNotificationCenter() |
| |
| public class NSNotificationCenter : NSObject { |
| |
| private var _observers: [NSNotificationReceiver] |
| private let _observersLock = NSLock() |
| |
| public required override init() { |
| _observers = [NSNotificationReceiver]() |
| } |
| |
| public class func defaultCenter() -> NSNotificationCenter { |
| return _defaultCenter |
| } |
| |
| public func postNotification(_ notification: NSNotification) { |
| |
| let sendTo = _observersLock.synchronized({ |
| return _observers.observersMatchingName(notification.name, sender: notification.object) |
| }) |
| |
| for observer in sendTo { |
| guard let block = observer.block else { |
| continue |
| } |
| |
| block(notification) |
| } |
| } |
| |
| public func postNotificationName(_ aName: String, object anObject: AnyObject?) { |
| let notification = NSNotification(name: aName, object: anObject) |
| postNotification(notification) |
| } |
| |
| public func postNotificationName(_ aName: String, object anObject: AnyObject?, userInfo aUserInfo: [NSObject : AnyObject]?) { |
| let notification = NSNotification(name: aName, object: anObject, userInfo: aUserInfo) |
| postNotification(notification) |
| } |
| |
| public func removeObserver(_ observer: AnyObject) { |
| removeObserver(observer, name: nil, object: nil) |
| } |
| |
| public func removeObserver(_ observer: AnyObject, name: String?, object: AnyObject?) { |
| guard let observer = observer as? NSObject else { |
| return |
| } |
| |
| _observersLock.synchronized({ |
| self._observers = _observers.filterOutObserver(observer, name: name, object: object) |
| }) |
| } |
| |
| public func addObserverForName(_ name: String?, object obj: AnyObject?, queue: NSOperationQueue?, usingBlock block: (NSNotification) -> Void) -> NSObjectProtocol { |
| if queue != nil { |
| NSUnimplemented() |
| } |
| |
| let object = NSObject() |
| |
| let newObserver = NSNotificationReceiver() |
| newObserver.object = object |
| newObserver.name = name |
| newObserver.block = block |
| newObserver.sender = obj |
| |
| _observersLock.synchronized({ |
| _observers.append(newObserver) |
| }) |
| |
| return object |
| } |
| |
| } |