2010-09-14 4 views
2

У меня вопрос об переопределении автогенерируемых методов доступа. Следующие не будут работать (я считаю), потому что каждый геттер ссылается на другого получателя. Существует ли правило, согласно которому методы доступа не должны использовать другие методы доступа, или вам просто нужно следить за этими ситуациями индивидуально?Аксессоры/Getters и Lazy Инициализация

-(UIImage *) image{ 

    if(image == nil){ 
     if(self.data == nil){ 
      [self performSelectorInBackground: @selector(loadImage) withObject: nil] 
     }else{ 
      self.image = [UIImage imageWithData: self.data]; 
     } 
    } 

    return image; 
} 

-(NSData *) data { 

    if(data == nil){ 
     if(self.image == nil){ 
      [self performSelectorInBackground: @selector(loadData) withObject: nil] 
     }else{ 
      self.data = UIImageJPEGRepresentation(self.image, 0.85); 
     } 
    } 

    return data; 
} 

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

ответ

3

Во-первых, не будьте слишком умны для вашего же блага. Если вы хотите преодолеть узкое место, сначала измерьте и убедитесь, что он действительно там. Я считаю, что и , и NSData выполняют некоторую внутреннюю ленивую загрузку, так что ваш код может быть практически бесполезным. Во-вторых, даже если вы действительно хотели сделать что-то подобное вручную, попробуйте разделить код кэширования на отдельный класс, чтобы вы не загрязняли код основного класса.

Существует не правило об аксессуарах (по крайней мере, об этом я знаю), потому что люди не делают много ленивой загрузки в аксессорах. Иногда я попадаю в бесконечную петлю, вызванную ленивым [UIViewController loadView] в сочетании с [UIViewController view], но об этом.

2

Там ничего не запрещает, но вы определенно пишете какой-то запутанный код. По сути, эти два свойства имеют круговую зависимость. Это трудно читать и отлаживать. Непонятно, почему вы хотите «загрузить данные» перед загрузкой изображения или почему вы также хотите поддерживать «загрузку изображения» перед загрузкой данных или, действительно, как два свойства действительно две разные вещи.

+0

Тот факт, что он является циркулярным, является тем, из чего возникают мои вопросы. –

0

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

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

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

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

Короче говоря, обычно это нормально (например, не ленивая инициализация), но этот конкретный дизайн (как сказал другой плакат) имеет круговую зависимость, которая должна быть минимизирована.

+0

спасибо, я имел в виду функции, чтобы не остановить поток - я обновил пример, чтобы оттолкнуть фоновые потоки (они, вероятно, вызывают обратные вызовы или уведомления по завершении) –

+0

pt1: относительно обновления: на самом деле лучше всего иметь поставщика данных выполнить фоновое изображение. в вашем примере любой простой доступ к члену может создать новый поток (то есть до тех пор, пока данные не будут готовы). поэтому было бы лучше, если бы поставщик данных отслеживал режимы (и потокобезопасные) на основе того, является ли он NotRequested, Fetching, Loaded - затем просто вызовите поставщика данных для загрузки изображения, когда изображение недоступно.если он NotRequested, начните загрузку в фоновом режиме, проигнорируйте запрос, если Fetching, else assert, так как данные должны быть удалены после извлечения. – justin

+0

pt2: блокировать обратные вызовы/обращения. со структурой, которую вы используете, вы можете создать один фоновый запрос для каждого доступа - что может означать, что вы запрашиваете несколько фоновых нагрузок и создаете новый поток при каждом доступе ==, вы можете в итоге получить 12 (или более) потоков, сообщающих поставщик данных для загрузки данных. – justin