我正在尝试检测Apple的GameKit用户身份验证视图何时被解雇并进入Cocos2D应用程序。我希望在用户通过身份验证后立即显示另一个视图,所以我只是想找到一个合适的触发器。
以下是我正在做的事情:遵循Apple的Game Center编程指南,我正在检查[[GKLocalPlayer localPlayer] isAuthenticated]
,如果用户未被授权,我正在设置authenticateHandler并保存返回的viewController,如下所示:
[GKLocalPlayer localPlayer].authenticateHandler = ^(UIViewController *viewController, NSError *error){
if (viewController != nil)
{
//save the returned view controller to show it when user tries to access leaderboards, etc.
_savedGCAuthViewController = viewController;
} else if([[GKLocalPlayer localPlayer] isAuthenticated]){
_userAuthenticated = YES;
}
};
我保存了返回的viewController,因此我可以在更合适的时间显示它:
AppController *appDelegate = (AppController *)[[UIApplication sharedApplication] delegate];
[appDelegate.navController presentViewController:_savedGCAuthViewController animated:YES completion:nil];
一切正常。问题是我无法知道该视图何时消失。
我在StackOverflow上看到的所有其他问题/答案都说在这种情况下将viewController子类化为viewDidDisappear方法,但是我不能将视图控制器子类化,因为Apple不提供访问GKHostedAuthenticateViewController类的标头。
我还在挖掘任何通知消息,但它看起来不像UIViewController使用任何NSNotificationCenter样式的消息。
想法?
我对iOS比较陌生,但有没有办法可以以某种方式进入视图层次结构并插入我自己的视图,当GKHostedAuthenticateViewController执行时会被处理掉?也许作为父视图控制器或孩子?
谢谢!
答案 0 :(得分:2)
您可以在呈现之前将GKHostedAuthenticateViewController
包装在您自己的控制器中,这样您就可以访问viewDidDisappear / viewWillDisappear方法:
// Simple class to wrap GKHostedAuthenticateViewController
class AuthController: UINavigationController {
var viewWillDisappearHandler: ((Bool) -> ())?
convenience init(authController: UIViewController) {
self.init(rootViewController: authController)
self.modalInPopover = true
self.modalPresentationStyle = UIModalPresentationStyle.FormSheet
self.navigationBarHidden = true
self.preferredContentSize = authController.preferredContentSize
}
override func viewWillDisappear(animated: Bool) {
super.viewWillDisappear(animated)
viewWillDisappearHandler?(animated)
}
}
然后在GKLocalPlayer.authenticateHandler
中,您可以设置viewWillDisappearHandler:
GKLocalPlayer.localPlayer().authenticateHandler = {
(viewController: UIViewController?, error: NSError?) -> Void in
if let viewController = viewController {
let authController = AuthController(authController: viewController)
authController.viewWillDisappearHandler = { (animated: Bool) -> () in
println("viewController is disappearing")
}
self.presentViewController(authController, animated: true, completion: nil)
} else {
// Authenticated
}
}
答案 1 :(得分:1)
由于某种原因,Game Center身份验证视图控制器是GKHostedAuthenticateViewController
的一个实例,它是我们不允许使用或引用的私有类。它没有任何方法可以干净地检测它何时被解除(与允许我们通过GKGameCenterViewController
协议的GKGameCenterControllerDelegate
实例不同。
此解决方案(读取变通方法)的工作原理是每隔一刻钟在后台进行测试,以查看视图控制器何时被解除。它并不漂亮,但它确实有效。
下面的代码应该是presentationViewController的一部分,它应该符合GKGameCenterControllerDelegate
协议。
提供Swift和Objective-C。
// Swift
func authenticateLocalUser() {
if GKLocalPlayer.localPlayer().authenticateHandler == nil {
GKLocalPlayer.localPlayer().authenticateHandler = { (gameCenterViewController: UIViewController?, gameCenterError: NSError?) in
if let gameCenterError = gameCenterError {
log.error("Game Center Error: \(gameCenterError.localizedDescription)")
}
if let gameCenterViewControllerToPresent = gameCenterViewController {
self.presentGameCenterController(gameCenterViewControllerToPresent)
}
else if GKLocalPlayer.localPlayer().authenticated {
// Enable GameKit features
log.debug("Player already authenticated")
}
else {
// Disable GameKit features
log.debug("Player not authenticated")
}
}
}
else {
log.debug("Authentication Handler already set")
}
}
func testForGameCenterDismissal() {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, Int64(0.25 * Double(NSEC_PER_SEC))), dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0)) {
if let presentedViewController = self.presentedViewController {
log.debug("Still presenting game center login")
self.testForGameCenterDismissal()
}
else {
log.debug("Done presenting, clean up")
self.gameCenterViewControllerCleanUp()
}
}
}
func presentGameCenterController(viewController: UIViewController) {
var testForGameCenterDismissalInBackground = true
if let gameCenterViewController = viewController as? GKGameCenterViewController {
gameCenterViewController.gameCenterDelegate = self
testForGameCenterDismissalInBackground = false
}
presentViewController(viewController, animated: true) { () -> Void in
if testForGameCenterDismissalInBackground {
self.testForGameCenterDismissal()
}
}
}
func gameCenterViewControllerDidFinish(gameCenterViewController: GKGameCenterViewController!) {
gameCenterViewControllerCleanUp()
}
func gameCenterViewControllerCleanUp() {
// Do whatever needs to be done here, resume game etc
}
注意:log.error和log.debug调用引用了XCGLogger:https://github.com/DaveWoodCom/XCGLogger
// Objective-C
- (void)authenticateLocalUser
{
GKLocalPlayer* localPlayer = [GKLocalPlayer localPlayer];
__weak __typeof__(self) weakSelf = self;
if (!localPlayer.authenticateHandler) {
[localPlayer setAuthenticateHandler:(^(UIViewController* viewcontroller, NSError* error) {
if (error) {
DLog(@"Game Center Error: %@", [error localizedDescription]);
}
if (viewcontroller) {
[weakSelf presentGameCenterController:viewcontroller];
}
else if ([[GKLocalPlayer localPlayer] isAuthenticated]) {
// Enable GameKit features
DLog(@"Player already authenticated");
}
else {
// Disable GameKit features
DLog(@"Player not authenticated");
}
})];
}
else {
DLog(@"Authentication Handler already set");
}
}
- (void)testForGameCenterDismissal
{
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.25 * NSEC_PER_SEC)), dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
if (self.presentedViewController) {
DLog(@"Still presenting game center login");
[self testForGameCenterDismissal];
}
else {
DLog(@"Done presenting, clean up");
[self gameCenterViewControllerCleanUp];
}
});
}
- (void)presentGameCenterController:(UIViewController*)viewController
{
BOOL testForGameCenterDismissalInBackground = YES;
if ([viewController isKindOfClass:[GKGameCenterViewController class]]) {
[(GKGameCenterViewController*)viewController setGameCenterDelegate:self];
testForGameCenterDismissalInBackground = NO;
}
[self presentViewController:viewController animated:YES completion:^{
if (testForGameCenterDismissalInBackground) {
[self testForGameCenterDismissal];
}
}];
}
- (void)gameCenterViewControllerDidFinish:(GKGameCenterViewController*)gameCenterViewController
{
[self gameCenterViewControllerCleanUp];
}
- (void)gameCenterViewControllerCleanUp
{
// Do whatever needs to be done here, resume game etc
}
答案 2 :(得分:-1)
从NSNotification
发布您自己的authenticateHandler
,表示它已完成。您的呈现视图控制器应该听取此通知。