2

Я в процессе преобразования моего проекта в использование ARC и столкнулся с особой проблемой. У меня есть класс, который управляет кешем файлов, загружаемых из сети. Каждый файл хранится в файловой системе iPhone, а связанный с ним объект хранится в моем классе менеджера для него. Другие объекты, которые хотят использовать файл, запрашивают мой менеджер для объекта кеша и сохраняют его до тех пор, пока ему нужен файл.автоматический подсчет ссылок (ARC) и retainCount

Но время от времени менеджер очищает кеш, удаляя старые файлы. Разумеется, он не должен удалять файлы, которые используются в данный момент. Перед АРК, я обнаружил, что при использовании retainCount связанного объекта:

// if retainCount is 1 then only the cache has a reference to it 
if(obj.retainCount <= 1) { 
    [obj deleteFile]; 
    [cache removeObject:obj]; 
} 

Это работало отлично [да, я знаю о предупреждениях о ненадежности retainCount, но по моему опыту, если retainCount> 1 вы знаете что более одного объекта сохранили его]

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

Знаете ли вы, что лучший способ достичь того же?

+0

Единственное, что стоит сказать для saveCount: http://stackoverflow.com/a/4636477/106435 – vikingosegundo

+0

Вы считали [NSCache] (https://developer.apple.com/library/ios/ # документация/какао/Справка/NSCache_Class/Справка/reference.html)? – Caleb

+0

@ Калеб: Роб просто дал этот ответ. Я не знал об этом и буду изучать его. – fishinear

ответ

5

Эта функция лучше всего обрабатывается NSCache и NSDiscardableContent. Это использует явные вызовы start и end, которые позволяют поддерживать сильные ссылки на вещи, которые вам не обязательно нужно хранить (потому что вы их автоматически создадите). Использование NSCache для этого также дает вам другие преимущества, такие как автоматический сброс отбрасываемого контента, даже если вы приостановлены. Без чего-то вроде NSCache, вы будете убиты, когда память опустится, а не позволит вам сбросить лишний кеш.

Тем не менее, вы создали другую систему. Эта конкретная проблема - это то, к чему относятся weak. Ваш кеш должен поддерживать слабую ссылку на объекты, а не на сильную ссылку. Существует несколько подходов, обсуждаемых в Non-retaining array for delegates. Я лично предпочитаю решение NSValue. Утвержденный ответ звучит великолепно и просто, но вам нужно хорошо понять ARC и CFArray, чтобы использовать его правильно. Решение NSValue намного менее сложно.

В идеале, если ваши файловые объекты знают, что они кэшированы, они могут указать кешу удалить их во время их dealloc. В противном случае вы можете периодически очищать пустые значения из массива.

+0

NSCache - хороший совет, я об этом не знал. Я обязательно посмотрю, смогу ли я это использовать. Слабые ссылки, которые я сначала думал, что я не могу использовать: это означало бы, что мои объекты и связанные файлы будут удалены, если они больше не используются. У меня есть кеш, чтобы этого избежать. Но думая об этом: я могу позволить объектам файла очищаться от слабых ссылок, но хранить файлы. Затем код очистки может проверить, какие ссылки равны нулю, и удалить связанные файлы. Mmmm, может работать. Благодаря! – fishinear

+0

Я посмотрел в NSCache, и, откровенно говоря, это не очень полезно. Несмотря на то, что он говорит, что он «включает различные политики автоматического удаления», похоже, что не существует способа установить политику для использования. Если вы знаете, как установить политику удаления LRU (или LFU), например, пожалуйста, дайте мне знать. Быстрый поиск в Интернете не дал полезных ответов. – fishinear

0

Просто установите некоторую переменную int в реализации объекта, увеличивайте ее каждый раз, когда объект сохраняется, и переопределите его метод dealloc, чтобы уменьшить его. Тот же счетчик хранения, но он хорош только для пользовательских объектов.

+0

Ну, dealloc моего файлового объекта не будет вызываться, потому что в моем кеше есть ссылка на него. Или вы имеете в виду деаллоки всех объектов, которые используют файловые объекты? Это будет то же самое, что настроить мою собственную систему подсчета ссылок, не так ли? – fishinear

+0

Он, вероятно, хотел уменьшить его в выпуске, а не dealloc. Я не уверен, что это будет работать, потому что я считаю, что ARC обходит обычные методы сохранения и выпуска и даже не позволяет вам переопределять их. – UIAdam

+0

@UIAdam, под ARC, это ошибка, чтобы вызвать сохранение или освобождение вообще. –

0

Не уверен, что это может быть применено к вашим потребностям, но знаете ли вы, что Associative References? Они позволяют привязать ведомые объекты к главному объекту, так что ведомый объект будет работать до тех пор, пока жив мастер. Это позволяет не только прикреплять объекты к объекту, у которого нет контроля, но вы также можете узнать об их окончании.

Интересно, можете ли вы использовать это для мониторинга вашего «obj», добавив к нему пользовательский объект класса и вызывается вызываемый класс «dealloc», если «obj» будет освобожден. В этом пользовательском dealloc вы можете выполнить удаление файла.

+0

Я не знал об ассоциативных ссылках, и они впечатляют, особенно вместе с категориями. Спасибо за совет! Однако в этом случае они неприменимы, поскольку я контролирую исходные объекты. Независимо от того, что я делаю в связанном объекте, я мог бы так же хорошо (in dealloc) исходного объекта. И я уже реализовал явный подсчет ссылок в исходных объектах, поэтому проблема уже не актуальна. – fishinear

Смежные вопросы