2016-07-14 20 views
1

最近在开发iOS应用程序时,我遇到了一个问题,我需要两个视图控制器共享一些数据,甚至从另一个视图控制器中检索UI状态。如果我使用委托进行视图控制器之间的通信,我将承担什么风险?

为了兑现这个特性,我定义并实现了视图控制器的委托。

@protocol ViewControllerADelegate <NSObject> 

-(id)dataForSomePurposeForViewController:(ViewController *)viewController 

@end 

,然后推一个新的viewController时(在ViewControllerA)类,我将在需要它设置currentViewController作为新的控制器的委托。

viewControllerA.delegate = currentViewController 
[currentViewController.navigationController pushViewController:viewControllerA animated:YES] 

后,我可以打电话委托选择和最后一个视图控制器获取数据,如:

//in viewControllerA 
self.someData = [self.delegate dataForSomePurposeForViewController:self] 

上面的代码只是一个例子展示了什么我都试过了,可能会有一些错字该代码并不会对此付出太多的关注。

事实上,上述方式工作正常,从未造成任何问题。但是当我和我的一位同事(谁是Android开发人员)讨论这个问题时,我被告知我在iOS中完成的操作在Android中不起作用。在Android的任务堆栈模型中,视图控制器(在Android中称为Activity)不会执行任何代码,也不会响应任何不在导航堆栈顶部的函数调用。

这不知怎么让我担心这样使用委托。我搜索了很多,现在我知道我的实现有点违背MVC设计模式,视图控制器之间通信的最佳方式可能是设置共享模型。

但是改变当前代码是一项耗时的任务。所以我的问题是:

  1. 使用委托视图控制器通信的风险是什么?
  2. 就我所知,拥有共享模型是最佳实践吗?如果是,我应该将这个模型分配给谁?通过使用单身?

任何帮助或思想的赞赏和感谢提前。

+0

这听起来像是Android版本应该推送和弹出碎片而不是不同的活动(然后他们可以使用这个委托模式没有问题),但如果他们已经建立了这样的应用程序,那么它会很多你们中的任何一方的工作都需要改变。也许只是针对每个平台有不同的实现,而不是世界末日。虽然可能会有影响,如果设计新的功能在此之上...很难说不知道你在做什么 – Fonix

+1

1)风险是堆栈顶层控制器可以不释放,如果你坚持强参考。将委托属性定义为弱。委托模式不仅是控制器之间进行通信的一种方式。您也可以使用区块或通知中心。它的风格问题。2)它取决于应用程序架构,有时候更适合共享模型,但在大多数情况下,代表有利于沟通。 –

+0

@BohdanSavy谢谢你的回复。事实上,我使用的是弱引用,可能委托并不是一个坏主意,至少对于iOS而言。如果你可以发表你的评论作为答案,那么也许我可以将其标记为已接受。 – MMhunter

回答

1

1)如果你持有强大的参考,风险在于堆栈顶层控制器不能解除分配。将委托属性定义为弱。委托模式不仅是控制器之间进行通信的一种方式。您也可以使用区块或通知中心。它的风格问题。2)它取决于应用程序体系结构,有时最好有共享模型,但在大多数情况下,代表有利于沟通。下面的示例。 与副本属性在firstViewController控制器上的一些行动创建类型块的属性 (why copy)

typedef void(^ApproveAction)(NSString *name);//return type(^name)(arguments) 

@interface SecondViewController : UIViewController 

@property (nonatomic, copy) ApproveAction onApproveTap; 

+ (NSString *)storyboardID; 

@end 

然后我们下一步:

#pragma mark - Actions 

- (IBAction)presentAction:(id)sender 
{ 
    SecondViewController *secondVC = [self.storyboard instantiateViewControllerWithIdentifier:[SecondViewController storyboardID]]; 
    secondVC.onApproveTap = ^(NSString *name) 
    { 
     NSLog(@"%@",name); 
    }; 

    [self presentViewController:secondVC animated:YES completion:nil]; 
} 

为了防止保留周期与块读取 this

话又说回来在SecondViewController调用块中,当您应该(例如在某个按钮上)时:

if (self.onApproveTap)//check if block not equal nil 
    self.onApproveTap(@"Name"); 

!self.onApproveTap?:self.onApproveTap(@"name");//the same but with syntax sugar 

希望这会有所帮助。

1

不知道dataForSomePurposeForViewController返回的数据类型以及它是如何生成的,作为您描述的控制器关系的一般设计选择,我会选择一种Dependency Injection实现,在该实现中传递所需的数据新的控制器。使用委托进行控制,例如将新控制器弹出堆栈,并将新控制器所做的更改保存在传递给它的模型上。

一些苹果核心数据的应用程序的examples涉及的划痕被管理对象的上下文(MOC)传递的创建成“添加新的记录的”包含数据控制器要由新的控制器操纵。该MOC由启动“添加”控制器的控制器创建并拥有,并且还负责在“添加”控制器弹出后将其拆除并保存更改。添加控制器的委托是启动它的控制器。

+0

感谢您的回复。我会了解MOC。但我仍然想知道如果我使用代表进行沟通是否存在风险。 'dataForSomePurposeForViewController'只是一个例子,在我真正的实现中,它可能是一个函数,它将参数和计算结果一起分配给旧控制器的一些属性。它基本上假定堆栈中的旧控制器将完成任何事情,就像它处于堆栈顶部时一样。 – MMhunter

+0

导航堆栈中的任何控制器都是“活动的”并且可以像任何对象一样访问。因为视图控制器包含的UINavigationController拥有这些控制器,所以它们保证在内存中,直到它们从导航堆栈弹出。 – jp2g

相关问题