iPhone / Cocoa Touch - проблема с многопоточностью (проект Stanford Presence 3) - PullRequest
0 голосов
/ 27 октября 2009

Я решаю проект по бесплатному курсу iPhone в Стэнфорде, который называется Presence 3 (находится на сайте Стэнфорда: www.stanford.edu/class/cs193p/cgi-bin/downloads.php), который извлекает данные из твиттера для пользователей, хранятся в виде списка. UIActivityIndicator (счетчик) виден во время загрузки данных. После загрузки данных TableView отображает пользователей в списке с их фотографиями, а пользовательские статусы отображаются при нажатии на ячейку пользователя. Я могу успешно отобразить TableView с фотографиями и вызвать другой контроллер представления со статусами при нажатии. Но когда я добавляю в спиннер, моя программа падает. Я настроил свою программу почти идентично примеру проекта ThreadedFlickrTableView, который также можно найти по той же ссылке выше (извините, я новый пользователь и могу публиковать только одну ссылку), что работает. Я установил точки останова в своем коде, чтобы увидеть, где была проблема, и обнаружил, что программа падает при загрузке ячейка в методе cellForRowAtIndexPath, особенно ru он извлекает фотографию из соответствующего массива (followeesPhotoURLs). Это связано с тем, что массив пуст - фотографии никогда не загружались, поскольку основной поток решает выполнить метод загрузки ячеек до того, как завершится выполнение потока, посвященного загрузке из Интернета (он начинает выполняться).

Я посмотрел на странице дискуссионной группы аудиторов курс и обнаружил, что у кого-то еще была такая же проблема, но тема никогда не решала проблему, и я написал по электронной почте безрезультатно: http://groups.google.com/group/iphone-appdev-auditors/browse_thread/thread/ccfc6ae99b4cf45d/ef1b8935e749c7c2?hl=en&lnk=gst&q=presence3#ef1b8935e749c7c2

Ответы [ 2 ]

1 голос
/ 27 октября 2009

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

Спиннер вращается во время загрузки ресурса. Таким образом, вы ожидаете ресурс, который может или не может быть готов, потому что вы не знаете точное состояние вашего фонового процесса. Как насчет установки значения в вашем основном потоке, указывающего, что вещи не готовы. Затем, когда ваш вторичный поток заканчивает загрузку, вы можете выполнить executeSelectorOnMainThread, чтобы заставить некоторую функцию основного потока установить значение, указывающее, что вы можете продолжить. Пока значение не говорит «продолжить», ваш основной поток не пытается получить доступ к тем значениям, которые могут касаться вспомогательного потока. Возможно, ваши ячейки будут отображать «загрузку» или подобное до тех пор, пока данные не будут готовы, или вы просто добавите ячейки, когда они будут готовы.

Еще одна вещь - только основной поток может касаться пользовательского интерфейса. Ничто в UIKit не является потокобезопасным, если не указано иное. Изменения индикатора прогресса должны обрабатываться основным потоком, он должен запускать индикатор и останавливать его (вероятно, когда ваш дополнительный поток уведомляет «выполнено», как указано выше).

0 голосов
/ 03 февраля 2010

Я только что закончил прорабатывать это сегодня, и вот последовательность событий, которые я наблюдал:

  1. Ваше табличное представление не будет загружено ничем, потому что ваши массивы ничего не содержат
  2. Ваш поток будет идти и получать данные Twitter
  3. Ваше табличное представление будет обновлено данными Twitter [self.tableView reloadData]

Если вы похожи на меня, вы пытаетесь установить имя пользователя, используя что-то похожее на

cell.textLabel.text = [[userInfo objectAtIndex:indexPath.row] valueForKey:@"name"];

Я думаю, что, поскольку он очень специфичен, приложение действительно пытается его найти и не возвращает ноль, если ничего не находит, в отличие от кода в примере, который

cell.text = [photoNames objectAtIndex:indexPath.row];

... поэтому ваше приложение выдает ошибку при первой попытке загрузки данных с пустыми массивами.

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

    // Set up the cell...
if ([userInfo count] == [userList count]) {

userInfo - это мой массив словарей с данными, полученными из Twitter.

userList - мой массив значений из списка свойств.

...