diff --git a/BeanCovertor.swift b/BeanCovertor.swift index fb286dfcd..bbb869ac7 100644 --- a/BeanCovertor.swift +++ b/BeanCovertor.swift @@ -179,8 +179,8 @@ func mapToLiveTranscoding(_ map: Dictionary) -> AgoraLiveTranscodin transcoding.transcodingExtraInfo = userConfigExtraInfo } if let transcodingUsers = map["transcodingUsers"] as? Array { - transcodingUsers.forEach { (item) in - if let item = item as? Dictionary { + transcodingUsers.forEach { + if let item = $0 as? Dictionary { transcoding.add(mapToTranscodingUser(item)) } } @@ -208,8 +208,8 @@ func mapToChannelMediaRelayConfiguration(_ map: Dictionary) -> Agor config.sourceInfo = mapToChannelMediaInfo(srcInfo) } if let destInfos = map["destInfos"] as? Array { - destInfos.forEach { (item) in - if let item = item as? Dictionary { + destInfos.forEach { + if let item = $0 as? Dictionary { let info = mapToChannelMediaInfo(item) config.setDestinationInfo(info, forChannelName: info.channelName ?? "") } diff --git a/Callback.swift b/Callback.swift index bf97af5c7..b911dfff8 100644 --- a/Callback.swift +++ b/Callback.swift @@ -17,14 +17,14 @@ protocol Callback: class { } extension Callback { - func code(_ code: Int32?, _ runnable: ((Int32) -> Any?)? = nil) { + func code(_ code: Int32?, _ runnable: ((Int32?) -> Any?)? = nil) { if code == nil || code! < 0 { let newCode = abs(Int(code ?? Int32(AgoraErrorCode.notInitialized.rawValue))) failure(String(newCode), AgoraRtcEngineKit.getErrorDescription(newCode) ?? "") return } - let res = runnable?(code!) + let res = runnable?(code) if res is Void { success(nil) } else { diff --git a/Extensions.swift b/Extensions.swift index d30ba931d..6f69f1596 100644 --- a/Extensions.swift +++ b/Extensions.swift @@ -144,8 +144,8 @@ extension AgoraRtcAudioVolumeInfo { extension Array where Element: AgoraRtcAudioVolumeInfo { func toMapList() -> Array> { var list = [Dictionary]() - self.forEach { (item) in - list.append(item.toMap()) + self.forEach { + list.append($0.toMap()) } return list } @@ -187,8 +187,8 @@ extension AgoraFacePositionInfo { extension Array where Element: AgoraFacePositionInfo { func toMapList() -> Array> { var list = [Dictionary]() - self.forEach { (item) in - list.append(item.toMap()) + self.forEach { + list.append($0.toMap()) } return list } diff --git a/MediaObserver.swift b/MediaObserver.swift index d90734e4b..0e853048f 100644 --- a/MediaObserver.swift +++ b/MediaObserver.swift @@ -43,9 +43,7 @@ extension MediaObserver: AgoraMediaMetadataDataSource { extension MediaObserver: AgoraMediaMetadataDelegate { func receiveMetadata(_ data: Data, fromUser uid: Int, atTimestamp timestamp: TimeInterval) { emitter([ - "buffer": String(data: data, encoding: .utf8), - "uid": uid, - "timeStampMs": timestamp + "data": [String(data: data, encoding: .utf8) ?? "", uid, timestamp] ]) } } diff --git a/RtcChannel.swift b/RtcChannel.swift index b27ab8094..08944703c 100644 --- a/RtcChannel.swift +++ b/RtcChannel.swift @@ -134,8 +134,8 @@ class RtcChannelManager: NSObject, RtcChannelInterface { } func Release() { - rtcChannelMap.forEach { key, value in - value.destroy() + rtcChannelMap.forEach { + $1.destroy() } rtcChannelMap.removeAll() rtcChannelDelegateMap.removeAll() @@ -149,10 +149,10 @@ class RtcChannelManager: NSObject, RtcChannelInterface { } @objc func create(_ params: NSDictionary, _ callback: Callback) { - callback.resolve(params["engine"] as? AgoraRtcEngineKit) { [weak self] it in - if let rtcChannel = it.createRtcChannel(params["channelId"] as! String) { - let delegate = RtcChannelEventHandler() { [weak self] methodName, data in - self?.emitter(methodName, data) + callback.resolve(params["engine"] as? AgoraRtcEngineKit) { [weak self] in + if let rtcChannel = $0.createRtcChannel(params["channelId"] as! String) { + let delegate = RtcChannelEventHandler() { [weak self] in + self?.emitter($0, $1) } rtcChannel.setRtcChannelDelegate(delegate) self?.rtcChannelMap[rtcChannel.getId()!] = rtcChannel @@ -196,8 +196,8 @@ class RtcChannelManager: NSObject, RtcChannelInterface { } @objc func getConnectionState(_ params: NSDictionary, _ callback: Callback) { - callback.resolve(self[params["channelId"] as! String]) { it in - it.getConnectionState().rawValue + callback.resolve(self[params["channelId"] as! String]) { + $0.getConnectionState().rawValue } } @@ -210,8 +210,8 @@ class RtcChannelManager: NSObject, RtcChannelInterface { } @objc func getCallId(_ params: NSDictionary, _ callback: Callback) { - callback.resolve(self[params["channelId"] as! String]) { it in - it.getCallId() + callback.resolve(self[params["channelId"] as! String]) { + $0.getCallId() } } @@ -286,8 +286,8 @@ class RtcChannelManager: NSObject, RtcChannelInterface { @objc func registerMediaMetadataObserver(_ params: NSDictionary, _ callback: Callback) { var code = -AgoraErrorCode.notInitialized.rawValue if let it = self[params["channelId"] as! String] { - let mediaObserver = MediaObserver { [weak self] data in - self?.emitter(RtcEngineEvents.MetadataReceived, data) + let mediaObserver = MediaObserver { [weak self] in + self?.emitter(RtcEngineEvents.MetadataReceived, $0) } if it.setMediaMetadataDelegate(mediaObserver, with: .video) { mediaObserverMap[it.getId()!] = mediaObserver @@ -309,14 +309,14 @@ class RtcChannelManager: NSObject, RtcChannelInterface { } @objc func setMaxMetadataSize(_ params: NSDictionary, _ callback: Callback) { - callback.resolve(mediaObserverMap[params["channelId"] as! String]) { it in - it.setMaxMetadataSize(params["size"] as! Int) + callback.resolve(mediaObserverMap[params["channelId"] as! String]) { + $0.setMaxMetadataSize(params["size"] as! Int) } } @objc func sendMetadata(_ params: NSDictionary, _ callback: Callback) { - callback.resolve(mediaObserverMap[params["channelId"] as! String]) { it in - it.addMetadata(params["metadata"] as! String) + callback.resolve(mediaObserverMap[params["channelId"] as! String]) { + $0.addMetadata(params["metadata"] as! String) } } @@ -356,7 +356,7 @@ class RtcChannelManager: NSObject, RtcChannelInterface { if let it = self[params["channelId"] as! String] { code = it.createDataStream(&streamId, reliable: params["reliable"] as! Bool, ordered: params["ordered"] as! Bool) } - callback.code(code) { it in + callback.code(code) { ignore in streamId } } diff --git a/RtcChannelEvent.swift b/RtcChannelEvent.swift index 19b7367cd..47144ae9a 100644 --- a/RtcChannelEvent.swift +++ b/RtcChannelEvent.swift @@ -220,23 +220,23 @@ extension RtcChannelEventHandler: AgoraRtcChannelDelegate { public func rtcChannel(_ rtcChannel: AgoraRtcChannel, didReceive event: AgoraChannelMediaRelayEvent) { callback(RtcChannelEvents.ChannelMediaRelayEvent, rtcChannel, event.rawValue) } - + func rtcChannel(_ rtcChannel: AgoraRtcChannel, didAudioPublishStateChange oldState: AgoraStreamPublishState, newState: AgoraStreamPublishState, elapseSinceLastState: Int) { callback(RtcChannelEvents.AudioPublishStateChanged, rtcChannel, rtcChannel.getId(), oldState.rawValue, newState.rawValue, elapseSinceLastState) } - + func rtcChannel(_ rtcChannel: AgoraRtcChannel, didVideoPublishStateChange oldState: AgoraStreamPublishState, newState: AgoraStreamPublishState, elapseSinceLastState: Int) { callback(RtcChannelEvents.VideoPublishStateChanged, rtcChannel, rtcChannel.getId(), oldState.rawValue, newState.rawValue, elapseSinceLastState) } - + func rtcChannel(_ rtcChannel: AgoraRtcChannel, didAudioSubscribeStateChange uid: UInt, oldState: AgoraStreamSubscribeState, newState: AgoraStreamSubscribeState, elapseSinceLastState: Int) { callback(RtcChannelEvents.AudioSubscribeStateChanged, rtcChannel, rtcChannel.getId(), uid, oldState.rawValue, newState.rawValue, elapseSinceLastState) } - + func rtcChannel(_ rtcChannel: AgoraRtcChannel, didVideoSubscribeStateChange uid: UInt, oldState: AgoraStreamSubscribeState, newState: AgoraStreamSubscribeState, elapseSinceLastState: Int) { callback(RtcChannelEvents.VideoSubscribeStateChanged, rtcChannel, rtcChannel.getId(), uid, oldState.rawValue, newState.rawValue, elapseSinceLastState) } - + func rtcChannel(_ rtcChannel: AgoraRtcChannel, rtmpStreamingEventWithUrl url: String, eventCode: AgoraRtmpStreamingEvent) { callback(RtcChannelEvents.RtmpStreamingEvent, rtcChannel, url, eventCode.rawValue) } diff --git a/RtcEngine.swift b/RtcEngine.swift index 08d787163..c3921c735 100644 --- a/RtcEngine.swift +++ b/RtcEngine.swift @@ -51,7 +51,7 @@ protocol RtcEngineInterface: func enableWebSdkInteroperability(_ params: NSDictionary, _ callback: Callback) func getConnectionState(_ callback: Callback) - + func sendCustomReportMessage(_ params: NSDictionary, _ callback: Callback) func getCallId(_ callback: Callback) @@ -67,7 +67,7 @@ protocol RtcEngineInterface: func setLogFileSize(_ params: NSDictionary, _ callback: Callback) func setParameters(_ params: NSDictionary, _ callback: Callback) - + func getNativeHandle(_ callback: Callback) } @@ -366,8 +366,8 @@ class RtcEngineManager: NSObject, RtcEngineInterface { } @objc func create(_ params: NSDictionary, _ callback: Callback) { - delegate = RtcEngineEventHandler() { [weak self] methodName, data in - self?.emitter(methodName, data) + delegate = RtcEngineEventHandler() { [weak self] in + self?.emitter($0, $1) } let config = AgoraRtcEngineConfig() config.appId = params["appId"] as? String @@ -377,7 +377,7 @@ class RtcEngineManager: NSObject, RtcEngineInterface { } @objc func destroy(_ callback: Callback) { - callback.resolve(engine) { [weak self] it in + callback.resolve(engine) { [weak self] ignore in self?.Release() } } @@ -416,18 +416,18 @@ class RtcEngineManager: NSObject, RtcEngineInterface { } @objc func getConnectionState(_ callback: Callback) { - callback.resolve(engine) { it in - it.getConnectionState().rawValue + callback.resolve(engine) { + $0.getConnectionState().rawValue } } - + @objc func sendCustomReportMessage(_ params: NSDictionary, _ callback: Callback) { callback.code(engine?.sendCustomReportMessage(params["id"] as! String, category: params["category"] as! String, event: params["event"] as! String, label: params["label"] as! String, value: params["value"] as! Int)) } @objc func getCallId(_ callback: Callback) { - callback.resolve(engine) { it in - it.getCallId() + callback.resolve(engine) { + $0.getCallId() } } @@ -450,10 +450,10 @@ class RtcEngineManager: NSObject, RtcEngineInterface { @objc func setLogFileSize(_ params: NSDictionary, _ callback: Callback) { callback.code(engine?.setLogFileSize((params["fileSizeInKBytes"] as! UInt))) } - + @objc func getNativeHandle(_ callback: Callback) { - callback.resolve(engine) { it in - Int(bitPattern: it.getNativeHandle()) + callback.resolve(engine) { + Int(bitPattern: $0.getNativeHandle()) } } @@ -470,14 +470,14 @@ class RtcEngineManager: NSObject, RtcEngineInterface { } @objc func getUserInfoByUserAccount(_ params: NSDictionary, _ callback: Callback) { - callback.resolve(engine) { it in - it.getUserInfo(byUserAccount: params["userAccount"] as! String, withError: nil)?.toMap() + callback.resolve(engine) { + $0.getUserInfo(byUserAccount: params["userAccount"] as! String, withError: nil)?.toMap() } } @objc func getUserInfoByUid(_ params: NSDictionary, _ callback: Callback) { - callback.resolve(engine) { it in - it.getUserInfo(byUid: params["uid"] as! UInt, withError: nil)?.toMap() + callback.resolve(engine) { + $0.getUserInfo(byUid: params["uid"] as! UInt, withError: nil)?.toMap() } } @@ -602,26 +602,26 @@ class RtcEngineManager: NSObject, RtcEngineInterface { } @objc func getAudioMixingPlayoutVolume(_ callback: Callback) { - callback.code(engine?.getAudioMixingPlayoutVolume()) { it in - it + callback.code(engine?.getAudioMixingPlayoutVolume()) { + $0 } } @objc func getAudioMixingPublishVolume(_ callback: Callback) { - callback.code(engine?.getAudioMixingPublishVolume()) { it in - it + callback.code(engine?.getAudioMixingPublishVolume()) { + $0 } } @objc func getAudioMixingDuration(_ callback: Callback) { - callback.code(engine?.getAudioMixingDuration()) { it in - it + callback.code(engine?.getAudioMixingDuration()) { + $0 } } @objc func getAudioMixingCurrentPosition(_ callback: Callback) { - callback.code(engine?.getAudioMixingCurrentPosition()) { it in - it + callback.code(engine?.getAudioMixingCurrentPosition()) { + $0 } } @@ -634,8 +634,8 @@ class RtcEngineManager: NSObject, RtcEngineInterface { } @objc func getEffectsVolume(_ callback: Callback) { - callback.resolve(engine) { it in - it.getEffectsVolume() + callback.resolve(engine) { + $0.getEffectsVolume() } } @@ -682,10 +682,10 @@ class RtcEngineManager: NSObject, RtcEngineInterface { @objc func resumeAllEffects(_ callback: Callback) { callback.code(engine?.resumeAllEffects()) } - + @objc func setAudioSessionOperationRestriction(_ params: NSDictionary, _ callback: Callback) { - callback.resolve(engine) { it in - it.setAudioSessionOperationRestriction(AgoraAudioSessionOperationRestriction(rawValue: params["restriction"] as! UInt)) + callback.resolve(engine) { + $0.setAudioSessionOperationRestriction(AgoraAudioSessionOperationRestriction(rawValue: params["restriction"] as! UInt)) } } @@ -762,8 +762,8 @@ class RtcEngineManager: NSObject, RtcEngineInterface { } @objc func isSpeakerphoneEnabled(_ callback: Callback) { - callback.resolve(engine) { it in - it.isSpeakerphoneEnabled() + callback.resolve(engine) { + $0.isSpeakerphoneEnabled() } } @@ -825,11 +825,11 @@ class RtcEngineManager: NSObject, RtcEngineInterface { @objc func registerMediaMetadataObserver(_ callback: Callback) { var code = -AgoraErrorCode.notInitialized.rawValue - if let it = engine { - let mediaObserver = MediaObserver { [weak self] data in - self?.emitter(RtcEngineEvents.MetadataReceived, data) + if let `engine` = engine { + let mediaObserver = MediaObserver { [weak self] in + self?.emitter(RtcEngineEvents.MetadataReceived, $0) } - if it.setMediaMetadataDelegate(mediaObserver, with: .video) { + if engine.setMediaMetadataDelegate(mediaObserver, with: .video) { self.mediaObserver = mediaObserver code = AgoraErrorCode.noError.rawValue } @@ -849,14 +849,14 @@ class RtcEngineManager: NSObject, RtcEngineInterface { } @objc func setMaxMetadataSize(_ params: NSDictionary, _ callback: Callback) { - callback.resolve(mediaObserver) { it in - it.setMaxMetadataSize(params["size"] as! Int) + callback.resolve(mediaObserver) { + $0.setMaxMetadataSize(params["size"] as! Int) } } @objc func sendMetadata(_ params: NSDictionary, _ callback: Callback) { - callback.resolve(mediaObserver) { it in - it.addMetadata(params["metadata"] as! String) + callback.resolve(mediaObserver) { + $0.addMetadata(params["metadata"] as! String) } } @@ -911,14 +911,14 @@ class RtcEngineManager: NSObject, RtcEngineInterface { } @objc func isCameraZoomSupported(_ callback: Callback) { - callback.resolve(engine) { it in - it.isCameraZoomSupported() + callback.resolve(engine) { + $0.isCameraZoomSupported() } } @objc func isCameraTorchSupported(_ callback: Callback) { - callback.resolve(engine) { it in - it.isCameraTorchSupported() + callback.resolve(engine) { + $0.isCameraTorchSupported() } } @@ -927,20 +927,20 @@ class RtcEngineManager: NSObject, RtcEngineInterface { } @objc func isCameraExposurePositionSupported(_ callback: Callback) { - callback.resolve(engine) { it in - it.isCameraExposurePositionSupported() + callback.resolve(engine) { + $0.isCameraExposurePositionSupported() } } @objc func isCameraAutoFocusFaceModeSupported(_ callback: Callback) { - callback.resolve(engine) { it in - it.isCameraAutoFocusFaceModeSupported() + callback.resolve(engine) { + $0.isCameraAutoFocusFaceModeSupported() } } @objc func setCameraZoomFactor(_ params: NSDictionary, _ callback: Callback) { - callback.resolve(engine) { it in - it.setCameraZoomFactor(CGFloat(params["factor"] as! Float)) + callback.resolve(engine) { + $0.setCameraZoomFactor(CGFloat(params["factor"] as! Float)) return nil } } @@ -950,15 +950,15 @@ class RtcEngineManager: NSObject, RtcEngineInterface { } @objc func setCameraFocusPositionInPreview(_ params: NSDictionary, _ callback: Callback) { - callback.resolve(engine) { it in - engine?.setCameraFocusPositionInPreview(CGPoint(x: params["positionX"] as! Double, y: params["positionY"] as! Double)) + callback.resolve(engine) { + $0.setCameraFocusPositionInPreview(CGPoint(x: params["positionX"] as! Double, y: params["positionY"] as! Double)) return nil } } @objc func setCameraExposurePosition(_ params: NSDictionary, _ callback: Callback) { - callback.resolve(engine) { it in - it.setCameraExposurePosition(CGPoint(x: params["positionXinView"] as! Double, y: params["positionYinView"] as! Double)) + callback.resolve(engine) { + $0.setCameraExposurePosition(CGPoint(x: params["positionXinView"] as! Double, y: params["positionYinView"] as! Double)) return nil } } @@ -968,15 +968,15 @@ class RtcEngineManager: NSObject, RtcEngineInterface { } @objc func setCameraTorchOn(_ params: NSDictionary, _ callback: Callback) { - callback.resolve(engine) { it in - it.setCameraTorchOn(params["isOn"] as! Bool) + callback.resolve(engine) { + $0.setCameraTorchOn(params["isOn"] as! Bool) return nil } } @objc func setCameraAutoFocusFaceModeEnabled(_ params: NSDictionary, _ callback: Callback) { - callback.resolve(engine) { it in - it.setCameraAutoFocusFaceModeEnabled(params["enabled"] as! Bool) + callback.resolve(engine) { + $0.setCameraAutoFocusFaceModeEnabled(params["enabled"] as! Bool) } } @@ -990,7 +990,7 @@ class RtcEngineManager: NSObject, RtcEngineInterface { if let it = engine { code = it.createDataStream(&streamId, reliable: params["reliable"] as! Bool, ordered: params["ordered"] as! Bool) } - callback.code(code) { it in + callback.code(code) { ignore in streamId } } diff --git a/RtcEngineEvent.swift b/RtcEngineEvent.swift index f303ef5a1..ed926d7d0 100644 --- a/RtcEngineEvent.swift +++ b/RtcEngineEvent.swift @@ -469,31 +469,31 @@ extension RtcEngineEventHandler: AgoraRtcEngineDelegate { public func rtcEngineVideoDidStop(_ engine: AgoraRtcEngineKit) { callback(RtcEngineEvents.VideoStopped) } - + func rtcEngine(_ engine: AgoraRtcEngineKit, firstLocalAudioFramePublished elapsed: Int) { callback(RtcEngineEvents.FirstLocalAudioFramePublished, elapsed) } - + func rtcEngine(_ engine: AgoraRtcEngineKit, firstLocalVideoFramePublished elapsed: Int) { callback(RtcEngineEvents.FirstLocalVideoFramePublished, elapsed) } - + func rtcEngine(_ engine: AgoraRtcEngineKit, didAudioPublishStateChange channel: String, oldState: AgoraStreamPublishState, newState: AgoraStreamPublishState, elapseSinceLastState: Int) { callback(RtcEngineEvents.AudioPublishStateChanged, channel, oldState.rawValue, newState.rawValue, elapseSinceLastState) } - + func rtcEngine(_ engine: AgoraRtcEngineKit, didVideoPublishStateChange channel: String, oldState: AgoraStreamPublishState, newState: AgoraStreamPublishState, elapseSinceLastState: Int) { callback(RtcEngineEvents.VideoPublishStateChanged, channel, oldState.rawValue, newState.rawValue, elapseSinceLastState) } - + func rtcEngine(_ engine: AgoraRtcEngineKit, didAudioSubscribeStateChange channel: String, withUid uid: UInt, oldState: AgoraStreamSubscribeState, newState: AgoraStreamSubscribeState, elapseSinceLastState: Int) { callback(RtcEngineEvents.AudioSubscribeStateChanged, channel, uid, oldState.rawValue, newState.rawValue, elapseSinceLastState) } - + func rtcEngine(_ engine: AgoraRtcEngineKit, didVideoSubscribeStateChange channel: String, withUid uid: UInt, oldState: AgoraStreamSubscribeState, newState: AgoraStreamSubscribeState, elapseSinceLastState: Int) { callback(RtcEngineEvents.VideoSubscribeStateChanged, channel, uid, oldState.rawValue, newState.rawValue, elapseSinceLastState) } - + func rtcEngine(_ engine: AgoraRtcEngineKit, rtmpStreamingEventWithUrl url: String, eventCode: AgoraRtmpStreamingEvent) { callback(RtcEngineEvents.RtmpStreamingEvent, url, eventCode.rawValue) } diff --git a/RtcSurfaceView.swift b/RtcSurfaceView.swift index cd69a26b7..9ae740cab 100644 --- a/RtcSurfaceView.swift +++ b/RtcSurfaceView.swift @@ -14,23 +14,27 @@ class RtcSurfaceView: UIView { private var surface: UIView private var canvas: AgoraRtcVideoCanvas private weak var channel: AgoraRtcChannel? - + override init(frame: CGRect) { - surface = UIView(frame: frame) + surface = UIView(frame: CGRect(origin: CGPoint(x: 0, y: 0), size: frame.size)) canvas = AgoraRtcVideoCanvas() canvas.view = surface super.init(frame: frame) addSubview(surface) - addObserver(self, forKeyPath: "frame", options: .new, context: nil) + addObserver(self, forKeyPath: observerForKeyPath(), options: .new, context: nil) + } + + func observerForKeyPath() -> String { + return "frame" } - + required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } - + deinit { canvas.view = nil - removeObserver(self, forKeyPath: "frame", context: nil) + removeObserver(self, forKeyPath: observerForKeyPath(), context: nil) } func setData(_ engine: AgoraRtcEngineKit, _ channel: AgoraRtcChannel?, _ uid: Int) { @@ -56,8 +60,10 @@ class RtcSurfaceView: UIView { } private func setupVideoCanvas(_ engine: AgoraRtcEngineKit) { - subviews.forEach { $0.removeFromSuperview() } - surface = UIView(frame: self.frame) + subviews.forEach { + $0.removeFromSuperview() + } + surface = UIView(frame: CGRect(origin: CGPoint(x: 0, y: 0), size: bounds.size)) addSubview(surface) canvas.view = surface if canvas.uid == 0 { @@ -88,10 +94,12 @@ class RtcSurfaceView: UIView { } } } - - override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) { - if keyPath == "frame" { - surface.frame = CGRect(x: 0, y: 0, width: self.frame.width, height: self.frame.height) + + override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey: Any]?, context: UnsafeMutableRawPointer?) { + if keyPath == observerForKeyPath() { + if let rect = change?[.newKey] as? CGRect { + surface.frame = CGRect(origin: CGPoint(x: 0, y: 0), size: rect.size) + } } } }