Я пытаюсь создать класс, который обработает несколько загрузок в то же время (я должен загрузить много маленьких файлов), и у меня есть проблемы с "исчезающими" соединениями.
У меня есть функция addDonwload, который добавляет URL к списку URL для загрузки и проверяет, существует ли доступный слот бесплатной загрузки. Если существует тот, он сразу запускает загрузку. Когда один из концов загрузок, я выбираю первый список формы URL и запускаю новую загрузку.
Я использую NSURLConnection для загрузки, вот некоторый код
- (bool) TryDownload:(downloadInfo*)info
{
int index;
@synchronized(_asyncConnection)
{
index = [_asyncConnection indexOfObject:nullObject];
if(index != NSNotFound)
{
NSLog(@"downloading %@ at index %i", info.url, index);
activeInfo[index] = info;
NSURLRequest *request = [NSURLRequest requestWithURL:info.url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:15];
[_asyncConnection replaceObjectAtIndex:index withObject:[[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:TRUE]];
//[[_asyncConnection objectAtIndex:i] scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
return true;
}
}
return false;
}
- (void)connectionDidFinishLoading:(NSURLConnection*)connection
{
[self performSelectorOnMainThread:@selector(DownloadFinished:) withObject:connection waitUntilDone:false];
}
- (void)DownloadFinished:(id)connection
{
NSInteger index = NSNotFound;
@synchronized(_asyncConnection)
{
index = [_asyncConnection indexOfObject:(NSURLConnection*)connection];
}
[(id)activeInfo[index].delegate performSelectorInBackground:@selector(backgroundDownloadSucceededWithData:) withObject:_data[index]];
[_data[index] release];
[activeInfo[index].delegate release];
@synchronized(_asyncConnection)
{
[[_asyncConnection objectAtIndex:index] release];
[_asyncConnection replaceObjectAtIndex:index withObject:nullObject];
}
@synchronized(downloadQueue)
{
[downloadQueue removeObject:activeInfo[index]];
[self NextDownload];
}
}
- (void)NextDownload
{
NSLog(@"files remaining: %i", downloadQueue.count);
if(downloadQueue.count > 0)
{
if([self TryDownload:[downloadQueue objectAtIndex:0]])
{
[downloadQueue removeObjectAtIndex:0];
}
}
}
_asyncConnection является моим массивом слотов загрузки (NSURLConnections) downloadQueue, список URL для загрузки
То, что происходит, вначале все работает хорошо, но после немногих загрузок мои соединения начинают исчезать. Загрузите запускается, но connection:didReceiveResponse: никогда не называется. Существует одна вещь в выходной консоли, что я не понимаю меня, который мог бы помочь немного. Normaly там - что-то как 24.01.2010 21:44:17.504 appName [3057:207] перед моими сообщениями NSLog. Я предполагаю, что число в квадратных скобках является некоторым app:thread идентификатором? все работает хорошо, в то время как существует то же число, но через какое-то время, "NSLog ("загрузка % в индексе %i", info.url, индекс)"; сообщения начинают иметь отличающийся что второе число. И когда это происходит, я прекращаю получать любые обратные вызовы для этого urlconnection.
Это сводило меня с ума, поскольку у меня есть строгие крайние сроки, и я не могу найти проблему. У меня нет многого опыта с iPhone dev и многопоточными приложениями. Я пробовал разные подходы, таким образом, мой код довольно грязен, но я надеюсь, что Вы будете видеть то, что я пытаюсь сделать здесь :)
btw, любой из Вас знаешь о существующем классе/lib, который я мог использовать, который будет полезен также. Я хочу параллельные загрузки со способностью o, динамично добавляют новые файлы для загрузки (настолько инициализирующий загрузчик вначале со всеми URL не полезен для меня),
В современных C++ обычно следует избегать указателей. Основная цель для указателей в наше время вращается вокруг того, что указатели могут быть полиморфными, тогда как явные объекты не.
, Когда вам нужен полиморфизм в наше время, хотя лучше использовать умный класс указателя - такой как станд.:: shared_ptr
(если ваш компилятор поддерживает C++ 0x расширения), станд.:: tr1:: shared_ptr
(если ваш компилятор не поддерживает C++ 0x, но действительно поддерживает TR1), или повышение:: shared_ptr
.
Обычно используются объекты.
Его легче съесть яблоко, чем яблоко на палочке (ОК 2 метровая палочка, потому что я люблю конфетные яблоки).
В этом случае просто сделать его вектором < gVector3 >
Если у вас был вектор < g3Vector * > это означает, что вы динамически распределяете новые объекты g3Vector (используя оператор new). Если это так, то вам нужно вызвать delete по этим указателям в какой-то момент и std:: Vector не предназначен для этого.
Но каждое правило является исключением.
Если g3Vector огромный объект, который стоит много, чтобы скопировать (трудно сказать прочитать вашу документацию), то это может быть более эффективным, чтобы сохранить в качестве указателя. Но в этом случае я бы использовал boost::ptr_vector
В этом коде имеется множество серьезных проблем с памятью и с синхронизацией потоков.
Вместо того, чтобы вдаваться в них все, я задам следующий вопрос: Вы делаете это на каком-то фоне? Почему? IIRC NSURLConnection уже загружает файлы в фоновом потоке и вызывает делегата в потоке, на котором был создан NSURLConnection (например, в идеале главный поток).
Предложите вам сделать шаг назад, перечитать документацию NSURLConnection, а затем удалить фоновый многопоточный код и всю сложность, которую вы без необходимости внесли в него.
Дальнейшее предложение: Вместо того, чтобы пытаться поддерживать параллельное позиционирование в двух массивах (и некоторый эскизный код в приведенном выше отношении), создайте один массив и получите объект, который содержит как NSURLConnection, ТАК И объект, представляющий результат. После завершения соединения можно просто освободить экземпляр соединения var. И родительский объект (и, следовательно, данные), когда вы закончите с данными.
Этот фрагмент может быть источником ошибки, вы освобождаете объект, на который указывает указатель activeInfo[index].delegate
сразу после вызова асинхронного метода на этот объект.
[(id)activeInfo[index].delegate performSelectorInBackground:@selector(backgroundDownloadSucceededWithData:) withObject:_data[index]];
[_data[index] release];
[activeInfo[index].delegate release];
Используете Подключение: DidFailwitherror:
? Может быть время ожидания, который предотвращает успешное завершение загрузки.
Старайтесь избавиться от @synchronized
блоков и посмотрите, что происходит.
Строка внутри квадратных скобок, кажется, идентификатор потоков, как вы уже догадались. Так что, возможно, вы заблокированы в @synchronized
. На самом деле, я не вижу причину для переключения нити - все проблемный код должен работать в основной ните ( PerfortSelectorOnmaintHaintHead
) ...
Во всяком случае, нет необходимости использовать оба @synchronized
и ShareSelectoronMaintHaintHead
.
Кстати, я не видел NSURLConnection * Connection = [[NSURLConnection Alloc] initWithRequest: Запрос делегата: Self];
линия. Где вы инициируете связь?
Как для параллельных загрузок - я думаю, что вы можете загрузить более одного файла за раз с тем же кодом, который вы используете здесь. Просто создайте отдельное соединение для каждой загрузки.
Рассмотрим, что оставьте очередь загрузки вместе с подсчетом активных подключений, выпрыгивающих элементов с верхней части очереди, когда загрузки загрузки и слот становится свободным. Затем вы можете отстрелить объекты NSURLConnection асинхронно и обрабатывать события на главной ните.
Если вы обнаружите, что ваш параллельный подход запрещает выполнять всю обработку на главной ните, рассмотрим, что объекты посредничества менеджера между основным потоком загрузки кода и NSURLConnection. Используя этот подход, вы могли бы создать свой менеджер и получить его, чтобы использовать NSURLConnection синхронно на фоновой резьбе. Затем этот менеджер полностью занимается загрузкой и передает результат назад к его основным делегатам потока с использованием PerfortSelectiononmaintHaintHead: withobject: call. Каждая загрузка - это просто случай создания нового объекта Manager, когда у вас свободный слот и настроив его.
После установки Android SDK создает для вас сертификат debug
подписи в хранилище ключей с именем debug.keystore
. Подключаемый модуль Eclipse использует этот сертификат для подписи каждой создаваемой сборки приложения.
К сожалению, сертификат отладки действителен только в течение 365 дней. Для создания нового файла необходимо удалить существующий файл debug.keystore
. Его расположение зависит от платформы - его можно найти в разделе Настройки - Android - Сборка - Хранилище отладочных ключей по умолчанию .
Дополнительные предметы для добавления в список, без особого порядка:
Я рекомендую вам взглянуть на это: http://allseeing-i.com/ASIHTTPRequest/
Это довольно сложный набор классов с либеральными условиями лицензирования (также бесплатными).
Это может обеспечить большую функциональность, которую вы хотите.