我在我的应用程序中实现了单例,但是当我在视图控制器之间切换时遇到了问题。
我的应用程序在一个视图控制器MainMenu中启动,然后在进行菜单选择时切换到游戏视图控制器。我在Game VC中有一个单例类,它是游戏的对象管理器(称为World)。它根据MainMenu中的菜单选择加载内容。我可以加载并退回MainMenu VC罚款。 Singleton工作得很好。当我再次从MainMenu中选择(从MainMenu VC到Game VC)时,我的应用程序崩溃导致NSAssert导致单例世界无法再分配,这是故意的。
如果没有尝试重新初始化我的单身人士,我怎样才能切换回游戏VC?
基本上,我想跳过Game VC的init方法中的[[world alloc] init]
行。我无法弄清楚如何正确地做到这一点......它需要能够在第一次(当世界不存在时)或任何后续时间(当世界已经作为单身存在时)被处理。我已经尝试了if (!world)
,但这不起作用。
这也引出了一个问题......我是否在正确的地方实施了我的单身人士?我应该把它放在MainMenu中吗?我只是想避免它在我在两个VC之间切换时尝试重新初始化/重新分配单例。
如果这有帮助,我将使用[self.view removeFromSuperview];
退出游戏VC我应该采用不同的方式吗?
答案 0 :(得分:2)
如果我正确理解了这个问题,你想知道如何创建一个Singleton类吗?最近的一种常见方式是使用大中心调度,如下所示:
+ (MyViewController*)shared
{
static dispatch_once_t onceToken;
static MyViewController* instance;
dispatch_once(&onceToken, ^
{
instance = [[[self class] alloc] init];
});
return instance;
}
然后您可以使用以下方式访问该实例:
[MyViewController shared];
在grand-central-dispatch之前,技术是在类上放置一个静态实例,并在调用共享访问器时检查它是否为nil。并且访问器需要用@synchronized(self)包装以确保线程安全。 GCD方式表现得更好一些。
话虽如此,我建议你使用有意志的单身人士。做一些关于它们被认为是反模式的研究,并研究依赖注入作为替代方案。
依赖注入与单身人士
单身人士的问题是他们可以导致紧密耦合。假设您正在建立航空公司预订系统。您的预订控制器可能使用:
id<FlightsClient>
在控制器中获取它的常用方法如下:
_flightsClient = [FlightsClient sharedInstance];
为了使用单例测试类,您现在必须同时测试单例,这可能会变得棘手,尤其是当您的应用程序变得更复杂时。想象一下,测试A级,取决于B级,取决于C级,取决于......没有多大乐趣!
另一种方法是使用依赖注入,这意味着使用初始化程序或属性设置程序将预订客户端传递给预订控制器。您可以手动执行此操作或使用库。如果你手动执行它仍然可以声明单例,尽管可能你不需要,因为顶级程序集类可以保留实例。
通过对单例使用这种替代方法,类将具有松耦合,并且易于测试和维护。 (使用依赖注入,你会有一个同样奇特的名字;))
我写了一个基于Spring的依赖注入库:https://github.com/jasperblues/spring-objective-c
答案 1 :(得分:1)
我能够通过确实将单例初始化移动到MainMenu视图控制器来解决这个问题。在我的设计中,该VC的init
仅在应用启动时调用一次,而每次切换到我的游戏VC中的自定义init
方法都被调用。
不确定这是否是我应该使用的最佳设计,但现在可以使用。