在不知道当前视图状态的情况下实现 openURL
Posted
技术标签:
【中文标题】在不知道当前视图状态的情况下实现 openURL【英文标题】:Implementing openURL without knowing the current view state 【发布时间】:2012-12-31 00:03:23 【问题描述】:我正在实现一个自定义 URL 方案,它将向我的数据模型添加实体。实体的详细信息包含在 URL 中。基本思想是电子邮件链接(或来自另一个应用程序的链接)将打开我的应用程序并添加新实体。
问题是,我永远无法确定我的应用在响应时会处于哪种状态。任何数量的视图控制器都可能在视图中。如果实体列表在视图中,我需要为该实体插入一个新行。如果屏幕上有其他视图,我需要做出不同的反应。有些视图也可能是模态的。
当这种情况发生时,我会对一个简单的模式感到满意 - 中止用户当前正在执行的任何操作,并弹出到根视图控制器。从这里我可能会推送到一个控制器,在那里我将显示正在添加的新实体。
我尝试总是关闭任何显示的模式并弹出到根目录,这样做的好处是不需要知道究竟显示了什么:
[(UINavigationController *)self.window.rootViewController dismissViewControllerAnimated:NO completion:nil];
[(UINavigationController *)self.window.rootViewController popToRootViewControllerAnimated:NO];
这工作相当不错,但至少有两种情况是不够的:
-
如果在呈现模式时创建了某个对象(然后使用模式来修改新对象),并且如果用户取消,则委托有责任删除该对象,该实体将保持活动状态。
如果正在显示
UIActionSheet
,则所有投注均已关闭。如果不知道显示它的控制器,可以访问该控制器并向其发送消息以关闭操作表,我就无法关闭它。如果不这样做,根视图控制器会弹出,但操作表会留在屏幕上。后续点击操作表当然会导致崩溃,因为显示它的控制器已经消失。
我该如何稳健地处理这个问题?我是否应该尝试具体找出当前呈现的视图控制器,并依次处理每个场景?或者是否有一个更具可扩展性的解决方案,每次我添加控制器或更改应用程序的流程时都不需要更新?
【问题讨论】:
【参考方案1】:听起来您正在尝试做几件事:
-
当用户点击您的自定义网址时,您希望向模型添加一个“实体”。
您希望以某种
EntityListViewController
的形式显示这个新实体,它可能在也可能不在 ViewController 堆栈上。
您(可能)想要弹出EntityListViewController
上方的所有视图控制器。
您希望用户知道添加了一个新实体(可能只是通过执行第 2 项)。
您想要推送某种EntityViewController
,或者如果视图控制器堆栈中当前存在EntityViewController
,您想要使用新实体的数据重新加载。
听起来您已经准备好了第 1 项,因为您没有明确询问处理 url 点击和插入新模型对象。
剩下的,一个灵活的 MVC 模式是使用 NSNotificationCenter。
插入新模型对象的代码会“发布”一个通知:
[[NSNotifcationCenter defaultCenter] postNotificationName:@"entity_added" object:myNewEntity];
然后您的各种 UI 元素(例如,UIAlertView 和 UIViewController 子类)将侦听此通知并采取一些有用的操作(例如关闭它们自己,或者在 EntityListViewController
或 EntityViewController
的情况下,重新加载它们自己)。
例如,UIViewController
子类可能会这样做:
-(void) viewDidLoad
[super viewDidLoad];
[[NSNoticationCenter defaultCenter] addObserver:self selector:@selector(onNewEntity:) name:@"entity_added" object:nil];
-(void) onNewEntity:(MyEntity*)entity
// close, or redraw or...
-(void) dealloc
[[NSNoticationCenter defaultCenter] removeObserver:self];
// if not using ARC, also call [super dealloc];
为了让你的生活保持简单(并且不要太担心所有不同的 UI 状态),我会考虑在通知发生时这样做:
-
让
EntityListViewController
重绘自身(不管上面是否有东西)。
在导航栏中(或您知道始终可见的其他位置)显示某种短暂的指示器,或播放声音让用户知道已添加实体。
仅此而已。
如果您采用这种方法,那么对用户正在/正在做的任何事情的影响都会很小,但是当他们确实导航回EntityListViewController
时,它已经显示了所有新实体。
显然,如果单击自定义 URL 可能会删除现有实体,那么弹出与该实体相关的任何视图控制器会更重要。但这也可以使用相同的模式来做——让模型或控制器发布通知,然后让各种 UI 元素监听它并采取适当的行动。
【讨论】:
感谢所有伟大的建议。我很可能会走这条路。这并不理想——我正在改变我想要的 UI 行为以适应技术限制——但似乎很务实。它也具有合理的可扩展性,但我必须确保我添加的任何新控制器都记得在必要时收听通知。我将尝试实施您的建议,看看效果如何。仍然会对一些万无一失的方法感兴趣,只需将我的应用程序踢回它的起始屏幕,从那里我可以做任何我喜欢的事情。 一个中途措施可能是到popToRootViewController
,但在你这样做之前,发出你即将这样做的通知。然后,您只需要在您提到的几个“特殊”位置收听该通知,例如应该在取消对象时删除对象的视图控制器,或者您的 UIActionSheet
的子类。
在任何情况下,我通常都继承 UIActionSheet
和 UIAlertView
,这是另一个很好的理由。在这些子类中,添加观察者的好地方是 initBlah,然后在 dealloc 中删除观察者。以上是关于在不知道当前视图状态的情况下实现 openURL的主要内容,如果未能解决你的问题,请参考以下文章