【问题标题】:Coordinating Controller design pattern in Cocoa TouchCocoa Touch 中的协调控制器设计模式
【发布时间】:2012-05-31 13:41:14
【问题描述】:

我正在创建一个带有大量自定义视图的 iOS 应用程序,因此,使用默认的 Cocoa 视图不是一个选项。然后,我决定采用 Coordinating / Mediator Controller 设计模式(在 Apress - Pro Objective-C Design Patterns for iOS 中学习)。

从委托中,我创建了一个 rootViewController 指向我的协调控制器中的视图:

self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
coordinatingController = [C6CoordinatingController sharedInstance];
self.window.rootViewController = coordinatingController.activeVC;
[self.window makeKeyAndVisible];
return YES;

然后,在协调控制器中,我有单例创建方法:

+ (C6CoordinatingController *) sharedInstance{
if (sharedCoordinator == nil){
    C6Log(@"New Shared Coordinator");
    sharedCoordinator = [[super allocWithZone:NULL] init];
    [sharedCoordinator initialize];
}
else {
    C6Log(@"Return Singleton Shared Coordinator");
}
return sharedCoordinator;
}



+ (id) allocWithZone:(NSZone *)zone{
return [self sharedInstance];
}



- (void) initialize{
C6Log(@"");
[self checkDevice];

_mainVC = [C6MainViewController initWithDevice:device];
_activeVC = _mainVC;
[self checkLanguage];
[self chooseFirstView];
}

我还有一个选择器可以选择第一个视图(我目前只有两个):

-(void) chooseFirstView{
// If a language was not setted, go to language settings view
if (!language) {
    C6Log(@"Going to Language Settings");
    C6LanguageSettingsViewController *languageVC = [C6LanguageSettingsViewController initWithDevice:device];
    [_mainVC.view addSubview:languageVC.view];
}
else {
    C6Log(@"Going to User Settings", language);
    C6AccountSettingsViewController *accountVC = [C6AccountSettingsViewController initWithDevice:device];
    [_mainVC.view addSubview:accountVC.view];
}
}

然后,我有一个 IBAction 供我的视图使用:

- (IBAction) requestViewChangeByObject:(id)object {
int buttonTag = [object tag]; // dividend
int viewTag = buttonTag / divisor; // quotient
int actionTag = buttonTag - (divisor * viewTag); // remainder
C6Log(@"viewTag: %d | actionTag %d", viewTag, actionTag);
switch (viewTag) {
    case LanguageTags:
        C6Log(@"LanguageTags");
        break;
    case AccountTags:
        C6Log(@"AccountTags");
        break;
    default:
        break;
}

在 NIB 中,我创建了一个 Obect(协调控制器)并从那里调用 IBAction。它工作得很好,我可以改变我的观点(它仍然需要实现)…………

但是……我也想更改语言,但是,因为这不是导航问题,所以我想从 C6LanguageSettingsViewController 而不是从 C6CoodinatingController 进行。

所以,我在 C6LanguageSettingsViewController 中创建了另一个 IBAction:

- (IBAction)chooseLang:(id)sender{
UIImage *bt;
[self resetImagesToNormalState];
C6Log(@""); 
C6Log(@"%@", [sender tag]);
C6Log(@"%@", sender);
.
.
.

当我将按钮连接到此 IBAction(通过 File's Owner 或通过 LanguageSettingsViewController 对象)时,应用程序中断,有时它没有显示错误,有时它显示 Unrecognized selector sent to instanceEXC_BAD_ACCESS (Code=1, address = 0x……) 在 UIApplicationMain 中。

我认为问题是 NIB 找不到文件的所有者……但我不知道如何解决它。

【问题讨论】:

    标签: iphone objective-c ios design-patterns cocoa-design-patterns


    【解决方案1】:

    好吧……这似乎很荒谬,但我正在回答自己:P

    我设法让它工作(终于!),我发现我正在以 BAAAAD 方式管理视图控制器,所以,我更改了协调控制器中的一些代码:

    首先,我没有一个“真正的”mainViewController,不再有 NIB 和 stuf……

    旧初始化

    - (void) initialize{
        C6Log(@"");
        [self checkDevice];
        _mainVC = [C6MainViewController initWithDevice:device];
        _activeVC = _mainVC;
        [self checkLanguage];
        [self chooseFirstView];
    }
    

    新初始化

    - (void) initialize{
        C6Log(@"");
        [self checkDevice];
        [self checkLanguage];
        [self chooseFirstView];
    }
    

    checkDevice 验证它是 iPhone 还是 iPad,所以我可以选择正确的 NIB。

    checkLanguage 检查语言的 [NSUserDefaults standardUserDefaults]

    最后,我调用了 chooseFirstView:

    OLD 选择FirstView

    -(void) chooseFirstView{
        // If a language was not setted, go to language settings view
        if (!language) {
            C6Log(@"Going to Language Settings");
            C6LanguageSettingsViewController *languageVC = [C6LanguageSettingsViewController initWithDevice:device];
            [_mainVC.view addSubview:languageVC.view];
        }
        else {
            C6Log(@"Going to User Settings", language);
            C6AccountSettingsViewController *accountVC = [C6AccountSettingsViewController initWithDevice:device];
            [_mainVC.view addSubview:accountVC.view];
        }
    }
    

    新选择第一视图

    -(void) chooseFirstView{
        // If a language was not setted, go to language settings view
        _activeVC = [[UIViewController alloc] init];
        UIImage *bgImage = [UIImage imageNamed:@"bg.png"];
        UIImageView *bgView = [[UIImageView alloc] initWithImage:bgImage];
        [_activeVC.view addSubview:bgView];
    
        if (!language) {
            C6Log(@"Going to Language Settings");
            languageVC = [C6LanguageSettingsViewController initWithDevice:device];
            [_activeVC.view addSubview:languageVC.view];
        }
        else {
            C6Log(@"Going to User Settings", language);
            accountVC = [C6AccountSettingsViewController initWithDevice:device];
            [_activeVC.view addSubview:accountVC.view];
        }
    }
    

    最大的变化是我何时以及如何启动 _activeVC……以及 _languageVC 和 _accountVC 现在都是全局变量这一事实。

    嗯,在此更改之后,NIB 按钮调用两个 IBAction 方法:它是文件的所有者和协调控制器。

    使用这种模式的另一件大事是如何在不爆炸 iOS 设备内存的情况下从一个视图更改为另一个视图……这是我在协调控制器中的操作方式:

    - (IBAction) requestViewChangeByObject:(id)object {
        int buttonTag = [object tag]; // dividend
        int viewTag = buttonTag / divisor; // quotient
        int actionTag = buttonTag - (divisor * viewTag); // remainder
        C6Log(@"ViewTag: %d", viewTag);
        switch (viewTag) {
            case LanguageTags:{
                C6Log(@"LanguageTags - button %d", actionTag);
                accountVC = [C6AccountSettingsViewController initWithDevice:device];
                UIView *fromView = languageVC.view;
                UIView *toView = accountVC.view;
                [self switchFrom:fromView To:toView usingAnimation:AnimationPushFromRigh];
            }
                break;
            case AccountTags:{
                C6Log(@"AccountTags - button %d", actionTag);
                switch (actionTag) {
                    case 0:{
                        C6Log(@"Go back");
                        languageVC = [C6LanguageSettingsViewController initWithDevice:device];
                        UIView *fromView = accountVC.view;
                        UIView *toView = languageVC.view;
                        [self switchFrom:fromView To:toView usingAnimation:AnimationPushFromLeft];
                    }
                        break;
    
                    default:
                        break;
                }
            }
                break;
            default:
                break;
        }
    }
    

    在方法的开始,我做了很多数学运算……我“创建”了一个模式,其中每个 NIB 的标签都应该以 100 倍数开头……所以,语言以 0 开头,帐户以 100 开头…………

    #define divisor         100
    #define LanguageTags    0
    #define AccountTags     1
    

    然后,我从一种视图切换到另一种视图的方式就在那里:

    -(void) switchFrom:(UIView*) fromView To:(UIView*) toView usingAnimation:(int) animation{
        C6Log(@"");
        /*************** SET ALL DEFAULT TRANSITION SETTINGS ***************/
        // Get the current view frame, width and height
        CGRect pageFrame = fromView.frame;
        CGFloat pageWidth = pageFrame.size.width;
        // Create the animation
        [UIView beginAnimations:nil context:nil];
        // Create the delegate, so the "fromView" is removed after the transition
        [UIView setAnimationDelegate: fromView];
        [UIView setAnimationDidStopSelector:@selector(removeFromSuperview)];
        // Set the transition duration
        [UIView setAnimationDuration: 0.4];
    
        // Add the "toView" as subview of "fromView" superview
        [fromView.superview addSubview:toView];
    
        switch (animation) {
            case AnimationPushFromRigh:{
                // Position the "toView" to the right corner of the page            
                toView.frame = CGRectOffset(pageFrame, pageWidth,0);
                // Animate the "fromView" to the left corner of the page
                fromView.frame = CGRectOffset(pageFrame, -pageWidth,0);
                // Animate the "toView" to the center of the page
                toView.frame = pageFrame;
                // Animate the "fromView" alpha
                fromView.alpha = 0;
                // Set and animate the "toView" alpha
                toView.alpha = 0;
                toView.alpha = 1;
    
                // Commit the animation
                [UIView commitAnimations];
            }
                break;
            case AnimationPushFromLeft:{
                // Position the "toView" to the left corner of the page         
                toView.frame = CGRectOffset(pageFrame, -pageWidth,0);
                // Animate the "fromView" to the right corner of the page
                fromView.frame = CGRectOffset(pageFrame, pageWidth,0);
                // Animate the "toView" to the center of the page
                toView.frame = pageFrame;
                // Animate the "fromView" alpha
                fromView.alpha = 0;
                // Set and animate the "toView" alpha
                toView.alpha = 0;
                toView.alpha = 1;
    
                // Commit the animation
                [UIView commitAnimations];
            }
                break;
            default:
                break;
        }
    }
    

    我真的希望这对尝试使用这种协调控制器模式的人有所帮助:P

    【讨论】:

      猜你喜欢
      • 2014-01-27
      • 1970-01-01
      • 1970-01-01
      • 2010-10-29
      • 2011-10-31
      • 2018-09-29
      • 2019-02-09
      • 2010-11-09
      • 2023-03-14
      相关资源
      最近更新 更多