【问题标题】:dispatch once issue in ios7 mrc在 ios7 mrc 中调度一次问题
【发布时间】:2015-04-07 21:35:03
【问题描述】:

在 iOS7 SDK 和使用 MRC 时,以下代码不会返回共享实例。在运行时它只是挂起并且不会移动到下一行代码。

+(id)getInstance
{
  static dispatch_once_t pred;
  static IAPManager *inAppManager = nil;
  dispatch_once(&pred, ^{
    inAppManager = [[IAPManager alloc] init];
  });
  return inAppManager;
}

这个异常的原因是什么?我就是这样称呼的

IAPManager *iapManager = [IAPManager getInstance];

if ([iapManager canMakePurchases]) {
    [iapManager loadStore:proUpgradeProductId];
}else{
    UIAlertView *aView = [[UIAlertView alloc]initWithTitle:@"" message:@"This device is not able or allowed to make payments" delegate:nil cancelButtonTitle:@"Ok" otherButtonTitles: nil];
    [aView show];
}

【问题讨论】:

  • 您对IAPManager init 的调用是否有可能最终调用getInstance?这会导致您描述的问题。
  • 它可能是。由于我没有明确调用 init 来返回 iAPManager self.. 这将调用 NSObject 中的 init。但无论如何我该如何克服这个问题。 :(
  • 编辑您的帖子以包含-[IAPManager init] 的定义。
  • @robmayoff 这是一个自定义类
  • IAPManagerinit 方法吗?如果是这样,请发布代码。

标签: objective-c ios7


【解决方案1】:

原始的 getInstance 方法绝对没问题(我将它声明为返回 IAPManager*,但它对它的工作方式没有任何影响)。 “静态”变量在任何地方都被初始化一次

问题很可能是从 [[IAPManager alloc] init] 调用 getInstance。从 dispatch_once 内部调用 dispatch_once 是一个即时死锁。要找出答案,您只需在 dispatch_once 语句的 getInstance 中设置一个断点。它应该在第一次调用期间被击中一次,然后可能再次被击中,原始调用将在堆栈上。或者只是等到它挂起,然后检查每个线程所在的调试器。你会发现一个线程正在等待 dispatch_once 完成。

另外,init 方法也有可能不返回。也许它做了一些没有完成的网络访问。要单步执行代码,请在块的第一(也是唯一)行设置断点,即 [[IAPManager alloc] init] 行。到达该断点后,您可以单步执行代码。

【讨论】:

  • 您必须仔细阅读该主题,然后随意否决答案! IAPManager 内部没有定义 init 方法,因此不会发生您所描述的死锁!
  • 不敢相信你已经批评和否决了其他用户的答案,而你甚至没有帮助解决问题。 "There has been so much useless advice on this thread." - 请不要在你的答案中加入这样的东西,如果你不同意一个答案然后投反对票并留下评论解释投反对票 -1 来解释我在你的答案中的不好评论,那就太粗鲁了已删除,但事实并非如此。
【解决方案2】:

在方法外部声明 inAppManager 对象。并使用以下代码

static IAPManager *inAppManager = nil;
+(id)getInstance
{

if (nil != inAppManager) {
        return inAppManager;
    }

  static dispatch_once_t pred;
  dispatch_once(&pred, ^{
    inAppManager = [[IAPManager alloc] init];
  });
  return inAppManager;
}

这可能对你有帮助。

谢谢

萨提亚

【讨论】:

  • 有些iAPManager实例是怎么存在的,所以如果出现EXC_BAD_ACCESS就满足第一个
  • 这称为反模式。请阅读静态变量的工作原理,以及 dispatch_once 的工作原理。
【解决方案3】:

试试这个:

+(instancetype)getInstance
{
  static id inAppManager;
  static dispatch_once_t pred;
  dispatch_once(&pred, ^{
    inAppManager = [[[self class] alloc] init];
  });
  return inAppManager;
}

【讨论】:

  • 我做到了,但仍然没有工作。虽然如果它进入块内它会调用一次它应该得到一个正确的实例..事情是..不会发生
  • 您是否在调试时单步执行代码并跟踪代码执行而卡住了?
  • 它是一个块.. 你不能跟随执行。一旦我调用 get 实例,它就不会进入调用类的下一行
  • 没错。你将不得不编写一个测试代码来检查这个方法。但请相信我,我已经使用并看到了很多这种模式,我认为它没有任何问题。但我不能说你的init 方法。
  • @M.Porooshani:static 变量只初始化一次,默认初始化为零。因此,如果你写 static IAPManager *inAppManager = nil;static IAPManager *inAppManager; 没有任何区别。
猜你喜欢
  • 2014-03-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-11-16
  • 2016-05-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多