Как избежать подсчета количества ссылок в _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 явно после того, как он мне больше не нужен.