Как избежать подсчета количества ссылок в _NSCFURLProtocolBridge в пользовательском NSURLProtocol в среде GC

У меня есть пользовательский NSURLProtocol. В startLoading, [self client] имеет тип:

<_NSCFURLProtocolBridge> {NSURLProtocol, CFURLProtocol}

Проблема заключается в том, что это выполняется в среде сбора мусора. Поскольку я пишу скринсейвер, я вынужден сделать сборку мусора. Однако протокол _NSCFURLProtocolBridge, похоже, всегда бросает:

malloc: reference count underflow for (memory_id_here), break on auto_refcount_underflow_error to debug

Пример дампа консоли отладки:

ScreenSaverEngine[1678:6807] client is <_NSCFURLProtocolBridge 0x20025ab00> {NSURLProtocol 0x200258ec0, CFURLProtocol 0x20029c400}  ScreenSaverEngine(1678,0x102eda000) malloc: reference count underflow for 0x20025ab00, break on auto_refcount_underflow_error to debug.

Вы можете видеть, что для <_NSCFURLProtocolBridge 0x20025ab00> происходит недополнение.

Когда я прерываю auto_refcount_underflow_error, кажется, что трассировка стека возвращается к URLProtocolDidFinishLoading: в:

id client = [self client];
...
[client URLProtocolDidFinishLoading:self];

Кажется, что эта проблема существовала какое-то время, но, похоже, ответа нет вообще в Интернете:

http://lists.apple.com/archives/cocoa-dev/2008/May/msg01272.html http://www.cocoabuilder.com/archive/message/cocoa/2007/12/17/195056

Ошибка также проявляется в средах, собранных для мусора, для этих перечисленных ошибок. Любые мысли о том, как я могу обойти это, не вызывая проблем с памятью? Я предполагаю, что это, вероятно, связано с тем, что тип CF под NSURLProtocol выпущен ненадлежащим образом?

Ответ 1

Последний WWDC мы подтвердили эту ошибку инженером webkit, он мог видеть ошибку прямо в коде, поэтому, надеюсь, они исправит ее. Обходной путь: CFRetain client в методе initWithRequest.

- (id)initWithRequest:(NSURLRequest *)request cachedResponse:(NSCachedURLResponse *)cachedResponse client:(id <NSURLProtocolClient>)client
{
    // work around for NSURLProtocol bug
    // note that this leaks!
    CFRetain(client);

    if (self = [super initWithRequest:request cachedResponse:cachedResponse client:client])
    {
    }

    return self;
}

Ответ 2

Это ошибка в реализации _NSCFURLProtocolBridge.

Пожалуйста, используйте http://bugreport.apple.com/ и укажите ошибку. Если вы укажете URL-адрес этой страницы, это будет оценено (и если вы обновите эту страницу с помощью Radar #, это тоже будет оценено). В идеале, если вы можете прикрепить двоичный файл вашей заставки, это будет очень полезно; не требуется источник.

К счастью, он не должен вызывать сбоев. К сожалению, это, вероятно, вызывает утечку.

Ответ 3

Эта ошибка обычно указывает, что объект был сохранен с помощью -retain, но выпущен с помощью CFRelease(). Если вы считаете, что это не может быть вашим объектом (и это не страшная вера), вам следует открыть другой радар. Но сначала вы должны осмотреть и посмотреть, есть ли объект CF, с которым вы используете -retain, когда, возможно, вы должны использовать CFRetain().

Остальная часть съемки снимается в темноте.

Вы можете получить некоторое представление, увеличив стек и посмотрев параметры, которые передаются этим методам С++ (или, в частности, auto_zone_release). Попробуйте это в gdb, чтобы посмотреть, что в первом параметре:

p *($esp)

И посмотрите, сможете ли вы получить представление о передаваемом объекте. Возможно, это сработает, если вам повезет:

po (id)(*($esp))

Ответ 4

Я работал над этой проблемой с помощью CFRetain -в клиента, а CFRelease - повторил его при следующем вызове startLoading

-(void)startLoading 
{
        if ( client ) CFRelease(client);
        client = [self client];
        CFRetain(client);

и, конечно, в финализации

-(void)finalize
{
    if ( client ) CFRelease(client);
    [super finalize];
}

client - это переменная экземпляра подкласса NSURLProtocol.

Ответ 5

Вот отчет об ошибке, который я подал некоторое время назад:

http://openradar.appspot.com/8087384

Вероятно, стоит подать заявку, он уже был обдуман, но было бы неплохо исправить его.

Как сказал Алекс, разработчик Apple посмотрел на исходный код передо мной и легко нашел проблему с примером, который у нас был.

Ответ 6

одна и та же ошибка приходит иногда с использованием NSURL в открытом диалоговом окне. для меня этого было достаточно, чтобы установить его на nil явно после того, как он мне больше не нужен.