| Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате |
| Форум программистов > iOS > Логика Apple |
| Автор: cosamia 3.12.2012, 02:19 |
| Попытка получить список из БД оканчивается неудачно У вьюконтроллера в методе viewDidLoad пишу: self.clients = [self.service getClients]; NSLog сколько клиентов получили Вот код Service: -(NSMutableArray*)getClients { NSMutableArray *array = [[NSMutableArray alloc] init]; if(![[NSFileManager defaultManager] fileExistsAtPath:[self.database.fileURL path]]) { return array; } else if (self.database.documentState ==UIDocumentStateClosed) { [self.database openWithCompletionHandler:^(BOOL success){ __block array = [self fetchDatabaseToGetData:self.database]; }]; return array; } else if (self.database.documentState ==UIDocumentStateNormal) { return [self fetchDatabaseToGetData:self.database]; } } -(NSMutableArray*)fetchDatabaseToGetData:(UIManagedDocument *)document { ... } Если бы этот код я написал под windows то под виндой он бы работал так: 1) как только выполняем операцию присвоения, идем в getClientsList 2) вызываем fetchDatabaseToGetData которая возвращает данные в getClientsList которые возвращают данные в self.clients Почему-то под эпл это работает по-другому, а именно: 1) первая строка дебагером вроде как пропускается потому что внутрь указанных методов я не попадаю но получаю NSLog сколько клиентов получили - а это уже строка 2 2) после этой чудесной логики я каким то чудом почему-то все-таки оказываюсь в getClientsList которая вызывает fetchDatabaseToGetData И возвращает правильный набор данных …но куда? self.clients уже содержат 0 клиентов потому как строка прошла, уже в прошлом Может быть знающие люди подскажут как работает логика эпл? Добавлено через 8 минут и 44 секунды Уточню логику эпл: После строки self.clients = [self.service getClients]; идет в getClients на линию [self.database openWithCompletionHandler:^(BOOL success){ __block array = [self fetchDatabaseToGetData:self.database]; }]; return array; Однако в fetchDatabaseToGetData:self.database не заходит и после чего возвращается в ViewController и пишет NSLog что 0 клиентов доходт до конца метода viewDidLoad после чего снова оказывается в getClients на линии [self.database openWithCompletionHandler:^(BOOL success){ __block array = [self fetchDatabaseToGetData:self.database]; }]; return array; после этого попадает в fetchDatabaseToGetData:self.database клиенты закидываются в локальный массив после чего завершает ViewController В результате ViewController содержит 0 полученных клиентов |
| Автор: Bitter 3.12.2012, 10:40 |
| это потому, что CompletionHandler выполняется в асинхронном режиме, то есть в параллельном потоке. А это значит, что после вызова openWithCompletionHandler метод завершается (судя по вашему коду) и возвращает массив на текущий момент. CompletionHandler выполнится тогда, когда до него дойдет очередь |
| Автор: cosamia 3.12.2012, 14:52 |
| Это я уже догадался. Но как с этим работать тогда? |
| Автор: Bitter 3.12.2012, 18:10 |
Это уже вам решать |
| Автор: cosamia 3.12.2012, 18:38 | ||
Я принимаю решения на основе анализа вариантов Для данного случая я не вижу вариантов и поэтому создал эту тему Если вы сталкивались с такой ситуаций, то поделитесь своим вариантом |
| Автор: Bitter 3.12.2012, 19:22 |
| Что тут сложного? Передавайте в ваш метод блок и выполняйте его в CompletionHandler |
| Автор: cosamia 4.12.2012, 03:18 | ||
Подробнее можно что и куда передавать? У меня есть Service класс который содержит метод -(NSMutableArray*)getClients; который в свою очередь вызывает другой метод этого же класса -(NSMutableArray*)fetchDatabaseToGetData:(UIManagedDocument *)document Таким образом класс Service представлен в виде DAL Теперь в контроллере мне надо вызвать этот метод что я и делаю путем self.array = [self getClient]; |
| Автор: Bitter 4.12.2012, 11:13 |
| Если ваш метод возвращает результаты в асинхронном режиме, то и обрабатывать их нужно в асинхронном режиме. Лучше всего для этого подходят блоки (http://idev.by/ios/21061/). В блоке описываете обработку массива и передаете его (блок) в свой метод getClient. |
| Автор: Bitter 5.12.2012, 10:44 |
| я говорю что в метод ваш вы должны передать блок. А в блоке написать то, что вам нужно. Например [myTable reloadData]; Вы можете написать например так (добавив в ваш метод блок в качестве параметра): [self.service getClientsWithCompletionHandler:^(id result) { self.clients = result; [myTable reloadData]; }]; блок вызываете в методе getClientsWithCompletionHandler там, где нужно (например вместо return array) |
| Автор: cosamia 6.12.2012, 02:13 |
| Я пытался сделать так(до прочтения этого ответа): [self.service ^(id result) { self.clients = result; [myTable reloadData]; }]; В результате ничего не сработало. Не знаю это идентично предложенному или нет.. В результате проблема была решена через делегаты |
| Автор: Bitter 6.12.2012, 10:53 |
| кусок кода, который вы написали - полная ерунда. Учите блоки |
| Автор: cosamia 7.12.2012, 19:28 |
| Я точно не помню что было написано, возможно что было написано так: self.clients= ^(something){[self.service getClients]}]; Помню что компилировалось но вылетало в рантайме |
| Автор: Bitter 7.12.2012, 22:56 | ||||
| ну в любом случае, вы написали что-то вроде: присвоить блок переменной self.clients. но поскольку переменная не типа "блок", то краш. Ну смотрите, можно было сделать так: 1. первым делом объявить тип вашего блока: typedef void (^MyCompletionHandler)(NSArray* result); 2. Метод getClient дополнить входящим параметром - блоком:
3. вызвать getClients передав в него блок:
|
| Автор: bales 20.12.2012, 23:55 |
| Ah I forgot, you can sign up for the newsletter here: http://mupromo.com The emails you'll get will be exactly what AppChest's hot deals feature does. Maybe that helps! |
| Автор: Nitehock1 5.1.2013, 20:14 |
| Здраствуйте мужики подскажите пожалуйста на iPhone 3GS кто знает возможно залить Android 4.1(хотяб 2.3) кто в курсе подскажите как или хотя бы что нужно и какую литературу читать. Спасибо |
| Автор: Bitter 5.1.2013, 20:20 |
| А новую тему создать слабо? |