从 Unity 桥接到 Swift 时通知中心不调用
Notification Center not calling when bridging from Unity to Swift
我们目前有一个 Unity(基于 C#)应用程序需要我们检测 iOS 中的音量按钮按下情况。我们目前通过 Objective-C++ 桥桥接本机 iOS 代码,并且该桥接我们的 Swift 代码。
我的想法是订阅公开的 AVSystemController
API 以在每次音量变化时告诉我们,但它似乎并没有在触发关联的通知时触发。我们这样设置:
VolumeDetector.mm
#import <Foundation/Foundation.h>
#import <MediaPlayer/MediaPlayer.h>
#import "unityswift-Swift.h"
@interface VolumeDetectorDelegateHandler: NSObject<VolumeDetectorDelegate>
@end
@implementation VolumeDetectorDelegateHandler
- (void)volumeDidChange {
UnitySendMessage("UIManager", "TakePicPressed", "Volume Changed");
}
@end
extern "C" {
void subscribeToVolumeButtons() {
VolumeDetector *detector = [VolumeDetector new];
VolumeDetectorDelegateHandler *handler = [VolumeDetectorDelegateHandler new];
detector.delegate = handler;
MPVolumeView *mpVolumeview = [MPVolumeView new];
[mpVolumeview setShowsVolumeSlider:NO];
detector.volumeView = mpVolumeview;
[detector subscribeToVolumeButtons];
}
}
VolumeDetector.swift
import Foundation
import UIKit
import MediaPlayer
@objc public protocol VolumeDetectorDelegate {
func volumeDidChange()
}
public class VolumeDetector: NSObject {
@objc public var delegate: VolumeDetectorDelegate?
@objc public var volumeView: MPVolumeView?
@objc func subscribeToVolumeButtons() {
print("Subscribing to volume buttons");
NotificationCenter.default.addObserver(self,
selector: #selector(volumeChanged(notification:)),
name: NSNotification.Name(rawValue: "AVSystemController_SystemVolumeDidChangeNotification"),
object: nil)
}
@objc func volumeChanged(notification: NSNotification) {
print("Volume changed")
if let userInfo = notification.userInfo {
if let volumeChangeType = userInfo["AVSystemController_AudioVolumeChangeReasonNotificationParameter"] as? String {
if volumeChangeType == "ExplicitVolumeChange" {
print("Explicit volume changed")
delegate?.volumeDidChange()
}
}
}
}
}
这种面向协议的设计适用于其他用例中的回调,但在这种情况下似乎没有调用 volumeChanged
。
我已经在原生 Xcode 项目中测试了这个确切的代码并且它有效..所以不用担心 'AVSystemController_SystemVolumeDidChangeNotification'.
有问题
解法:
正如 Rob Napier 指出的那样,我必须保持对委托处理程序的强引用,以便观察者可以在附近逗留。这是更新后的工作代码:
VolumeDetector.mm
#import <Foundation/Foundation.h>
#import <MediaPlayer/MediaPlayer.h>
#import "unityswift-Swift.h"
@interface VolumeDetectorDelegateHandler: NSObject<VolumeDetectorDelegate>
@property (strong, retain) VolumeDetector *detector;
@property (strong, retain) MPVolumeView *volumeView;
@end
static VolumeDetectorDelegateHandler *handler;
@implementation VolumeDetectorDelegateHandler
- (void) subscribeToVolButtons {
_detector = [VolumeDetector new];
_detector.delegate = handler;
[_detector subscribeToVolumeButtons];
}
-(void)volumeDidChange {
UnitySendMessage("UIManager", "TakePicPressed", "Volume Changed");
}
@end
extern "C" {
void subscribeToVolumeButtons() {
handler = [VolumeDetectorDelegateHandler new];
[handler subscribeToVolButtons];
}
}
VolumeDetector.swift
import Foundation
import UIKit
import MediaPlayer
@objc public protocol VolumeDetectorDelegate {
func volumeDidChange()
}
public class VolumeDetector: NSObject {
@objc public var delegate: VolumeDetectorDelegate?
@objc func subscribeToVolumeButtons() {
if let vc = UnityGetGLViewController() {
let volumeView = MPVolumeView(frame: CGRect(x:-100, y:0, width:0, height:0))
volumeView.showsRouteButton = false
vc.view.addSubview(volumeView);
NotificationCenter.default.addObserver(self,
selector: #selector(volumeChanged(notification:)),
name: NSNotification.Name(rawValue: "AVSystemController_SystemVolumeDidChangeNotification"),
object: nil)
}
}
@objc func volumeChanged(notification: NSNotification) {
if let userInfo = notification.userInfo {
if let volumeChangeType = userInfo["AVSystemController_AudioVolumeChangeReasonNotificationParameter"] as? String {
if volumeChangeType == "ExplicitVolumeChange" {
delegate?.volumeDidChange()
}
}
}
}
}
您在 subscribeToVolumeButtons()
中创建了一个检测器,它订阅了通知,然后您立即丢弃了该检测器。到那时,您应该期望它会自动取消订阅通知。如果您希望检测器留在周围并继续运行,您将需要一些对它有强烈参考的东西。
如果您将 deinit
添加到 VolumeDetector
,我预计它会在 subscribeToVolumeButtons()
returns.
后不久被触发
我们目前有一个 Unity(基于 C#)应用程序需要我们检测 iOS 中的音量按钮按下情况。我们目前通过 Objective-C++ 桥桥接本机 iOS 代码,并且该桥接我们的 Swift 代码。
我的想法是订阅公开的 AVSystemController
API 以在每次音量变化时告诉我们,但它似乎并没有在触发关联的通知时触发。我们这样设置:
VolumeDetector.mm
#import <Foundation/Foundation.h>
#import <MediaPlayer/MediaPlayer.h>
#import "unityswift-Swift.h"
@interface VolumeDetectorDelegateHandler: NSObject<VolumeDetectorDelegate>
@end
@implementation VolumeDetectorDelegateHandler
- (void)volumeDidChange {
UnitySendMessage("UIManager", "TakePicPressed", "Volume Changed");
}
@end
extern "C" {
void subscribeToVolumeButtons() {
VolumeDetector *detector = [VolumeDetector new];
VolumeDetectorDelegateHandler *handler = [VolumeDetectorDelegateHandler new];
detector.delegate = handler;
MPVolumeView *mpVolumeview = [MPVolumeView new];
[mpVolumeview setShowsVolumeSlider:NO];
detector.volumeView = mpVolumeview;
[detector subscribeToVolumeButtons];
}
}
VolumeDetector.swift
import Foundation
import UIKit
import MediaPlayer
@objc public protocol VolumeDetectorDelegate {
func volumeDidChange()
}
public class VolumeDetector: NSObject {
@objc public var delegate: VolumeDetectorDelegate?
@objc public var volumeView: MPVolumeView?
@objc func subscribeToVolumeButtons() {
print("Subscribing to volume buttons");
NotificationCenter.default.addObserver(self,
selector: #selector(volumeChanged(notification:)),
name: NSNotification.Name(rawValue: "AVSystemController_SystemVolumeDidChangeNotification"),
object: nil)
}
@objc func volumeChanged(notification: NSNotification) {
print("Volume changed")
if let userInfo = notification.userInfo {
if let volumeChangeType = userInfo["AVSystemController_AudioVolumeChangeReasonNotificationParameter"] as? String {
if volumeChangeType == "ExplicitVolumeChange" {
print("Explicit volume changed")
delegate?.volumeDidChange()
}
}
}
}
}
这种面向协议的设计适用于其他用例中的回调,但在这种情况下似乎没有调用 volumeChanged
。
我已经在原生 Xcode 项目中测试了这个确切的代码并且它有效..所以不用担心 'AVSystemController_SystemVolumeDidChangeNotification'.
有问题解法:
正如 Rob Napier 指出的那样,我必须保持对委托处理程序的强引用,以便观察者可以在附近逗留。这是更新后的工作代码:
VolumeDetector.mm
#import <Foundation/Foundation.h>
#import <MediaPlayer/MediaPlayer.h>
#import "unityswift-Swift.h"
@interface VolumeDetectorDelegateHandler: NSObject<VolumeDetectorDelegate>
@property (strong, retain) VolumeDetector *detector;
@property (strong, retain) MPVolumeView *volumeView;
@end
static VolumeDetectorDelegateHandler *handler;
@implementation VolumeDetectorDelegateHandler
- (void) subscribeToVolButtons {
_detector = [VolumeDetector new];
_detector.delegate = handler;
[_detector subscribeToVolumeButtons];
}
-(void)volumeDidChange {
UnitySendMessage("UIManager", "TakePicPressed", "Volume Changed");
}
@end
extern "C" {
void subscribeToVolumeButtons() {
handler = [VolumeDetectorDelegateHandler new];
[handler subscribeToVolButtons];
}
}
VolumeDetector.swift
import Foundation
import UIKit
import MediaPlayer
@objc public protocol VolumeDetectorDelegate {
func volumeDidChange()
}
public class VolumeDetector: NSObject {
@objc public var delegate: VolumeDetectorDelegate?
@objc func subscribeToVolumeButtons() {
if let vc = UnityGetGLViewController() {
let volumeView = MPVolumeView(frame: CGRect(x:-100, y:0, width:0, height:0))
volumeView.showsRouteButton = false
vc.view.addSubview(volumeView);
NotificationCenter.default.addObserver(self,
selector: #selector(volumeChanged(notification:)),
name: NSNotification.Name(rawValue: "AVSystemController_SystemVolumeDidChangeNotification"),
object: nil)
}
}
@objc func volumeChanged(notification: NSNotification) {
if let userInfo = notification.userInfo {
if let volumeChangeType = userInfo["AVSystemController_AudioVolumeChangeReasonNotificationParameter"] as? String {
if volumeChangeType == "ExplicitVolumeChange" {
delegate?.volumeDidChange()
}
}
}
}
}
您在 subscribeToVolumeButtons()
中创建了一个检测器,它订阅了通知,然后您立即丢弃了该检测器。到那时,您应该期望它会自动取消订阅通知。如果您希望检测器留在周围并继续运行,您将需要一些对它有强烈参考的东西。
如果您将 deinit
添加到 VolumeDetector
,我预计它会在 subscribeToVolumeButtons()
returns.