Почему доза NSString стала NSZomie в этом коде? - PullRequest
0 голосов
/ 07 июля 2019

Я только что столкнулся с проблемой. Я использую NSMutableArray, чтобы сохранить идентификаторы объявлений, которые необходимо загрузить.Когда один идентификатор предварительно загружен, я удаляю его из массива.Затем я узнаю, что после удаления идентификатор устройства превратился в зомби.

Я попытался воспроизвести это, и я обнаружил, что когда идентификатор объявления был извлечен из массива, это не зомби. Это простостать зомби после удаления из массива.Но есть еще ссылка NSString *, как это может произойти?И если он станет зомби на этом этапе, он должен стать зомби каждый раз.Но это происходит только изредка.

 -(void)preloadNextRewardVideo
 {
     if([_allRewardVideoAds count])
     {
         NSString* adsName = [_allRewardVideoAds objectAtIndex:0];  //the element is not a zombie here
         GADRewardBasedVideoAd* ads = [self ensureRewardVideo:adsName];
         if(![ads isReady])
         {
             _currentRewardVideoName = adsName;
             [_allRewardVideoAds removeObjectAtIndex:0];
             GADRequest *request = [GADRequest request];
             [ads loadRequest:request withAdUnitID:adsName];  //here, adsName is a zombie
             _isRewarLoading = YES;
         }
     }
 }

Ответы [ 2 ]

1 голос
/ 08 июля 2019

Поскольку вы не включаете ARC, это означает, что вам нужно вручную управлять памятью. Поскольку вы не включаете ARC, это означает, что вам нужно вручную управлять памятью. Несмотря на то, что большинство API возвратит автоматически освобожденный объект из метода, но это не всегда так.

В этом случае NSArray сохраняет содержащиеся в нем объекты, поэтому может не потребоваться возвращать автоматически освобожденный объект из objectAtIndex: method, поскольку он должен быть сохранен сам по себе в качестве оптимизации. В этом случае я предлагаю вам вызвать retain объекта, когда вы получите его из массива, и освободить его до конца этого метода. Это помогло бы в этом случае.

1 голос
/ 08 июля 2019

Стоит внимательно взглянуть на политику управления памятью .Дело в том, что (как мне кажется), когда ваш код назначает строку adsName, объект, частью которого является метод preloadNextRewardVideo, не становится владельцем объекта string, на который указывает adsName («владение»).в этом контексте означает либо выделение и инициализацию пространства для него с помощью alloc / init, new, copy и т. д., либо отправку ему явного сообщения сохранения).Все, что у вас есть, это локальная переменная, которая указывает на строковый объект, принадлежащий массиву _allRewardVideoAds.Да, выполнение присваивания увеличивает количество сохранений, но это сохранение автоматически высвобождается и ограничивается областью применения этого метода.Как только этот метод завершится, ничему не будет принадлежать этот строковый объект, и он будет освобожден.

Это не будет проблемой (и не создаст флаг NSZombie), за исключением того, что вы только что отправили adsName к другому объекту (GADRewardBasedVideoAd* ads), который, как я предполагаю, тоже не сохраняет его.Конечно, ads также автоматически освобождается (ничто не владеет им вне этого метода), но что это, состояние гонки по поводу того, сначала ли ads или adsName освобождается?Я подозреваю, что у вас действительно есть состояние гонки, потому что NSZombie появляется только иногда, но я недостаточно знаю о внутренних механизмах автоматического выпуска, чтобы знать, как это может работать.

Я думаю, что NSZombie просто говорит вам, что у вас есть объект, который:

  • используется внешним объектом и
  • из-за скорого уничтожения, хотяautorelease.

ARC ожидает проблему и использует NSZombie, чтобы сообщить вам.

Вы можете исправить это либо с помощью установщика свойств (например, используйте self.currentRewardVideoName = adsName), который сохраняет строку-объект глобально для этого объекта или локально скопировав его (NSString* adsName = [[_allRewardVideoAds objectAtIndex:0] copy]), который гарантирует, что ваш объект владеет строкой до конца метода.

...