Использование ivar в блоке, возвращаемом другому объекту - PullRequest
2 голосов
/ 01 июля 2010

Я обнаружил сбой в приложении для iPhone с целевой iOS 4, который меняется в зависимости от типа сборки.

Отладчик ничего не дает, он останавливается на

 UIViewController *result = [self factory](self);

с EXC_BAD_ACCESS. self - это класс, унаследованный от NSObject (показан ниже как NSObjectInheritor). Зомби включены. Я попытался изменить метод factory тремя способами со следующими результатами.

Это приводит к сбою в отладочной и специальной сборках ...

- (FactoryMethod) factory;
{
    return [^ UIViewController * (NSObjectInheritor *newThing)
    {
      return [[ViewControllerClass alloc] initWithStuff:(boolValue ? foo : bar)];
    } autorelease];
}

Это работает в отладочных сборках, но аварийно завершает работу ...

- (FactoryMethod) factory;
{
  return [^ UIViewController * (NSObjectInheritor *newThing)
  {
    if(boolValue)
    {
      return [[ViewControllerClass alloc] initWithStuff:foo];
    }
    else
    {
      return [[ViewControllerClass alloc] initWithStuff:bar];
    }
  } autorelease];
}

Это работает как в режиме отладки, так и в режиме ad hoc, но очень уродливо и избыточно:

- (FactoryMethod) factory;
{
  if(boolValue)
  {
    return [^ UIViewController * (NSObjectInheritor *newThing)
    {
      return [[ViewControllerClass alloc] initWithStuff:foo];
    } autorelease];
  }
  else
  {
    return [^ UIViewController * (NSObjectInheritor *newThing)
    {
      return [[[ViewControllerClass alloc] initWithStuff:bar];
    } autorelease];
  }
}

Моя теория состоит в том, что boolValue становится недоступным во время выполнения возвращаемого блока. Это

@interface SubclassOfNSObjectInheritor : NSObjectInheritor
{
  BOOL boolValue;
}

@property (readonly) BOOL boolValue;

(YES или NO присваивается в инициализации SubclassOfNSObjectInheritor) и

@synthesize boolValue;

в реализации SubclassOfNSObjectInheritor.

Последний вопрос: верна ли моя теория о том, что неправильно? Третий способ сделать это - отмеченный как работа в специальных и отладочных сборках - безопасен? Каков наилучший способ сделать это?

1 Ответ

6 голосов
/ 01 июля 2010

Ваша проблема двоякая: во-первых, вы перевыпускаете свой блок, а во-вторых, блоки создаются в стеке, который исчезает, когда ваш метод возвращается (вы в основном возвращаете указатель в ранее разрушенный кадр стека).

Вместо этого скопируйте блок и автоматически отпустите его перед возвратом. Вы можете сделать это целевым способом c сообщением copy, а вы можете вызвать функцию Block_copy().

Ваш сбой в различных конфигурациях - чистая случайность. Итак, чтобы исправить одну из ваших реализаций:

- (FactoryMethod) factory;
{
  return [[^(NSObjectInheritor *newThing)
  {
    if(boolValue)
    {
      return [[ViewControllerClass alloc] initWithStuff:foo];
    }
    else
    {
      return [[ViewControllerClass alloc] initWithStuff:bar];
    }
  } copy] autorelease];
}
...