Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Логика Apple 
:(
    Опции темы
cosamia
Дата 3.12.2012, 02:19 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 231
Регистрация: 11.5.2005

Репутация: нет
Всего: нет



Попытка получить список из БД оканчивается неудачно
    
У вьюконтроллера в методе 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 полученных клиентов

Это сообщение отредактировал(а) cosamia - 3.12.2012, 02:19
PM   Вверх
Bitter
Дата 3.12.2012, 10:40 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный лентяй
***


Профиль
Группа: Завсегдатай
Сообщений: 1209
Регистрация: 15.8.2004
Где: Харьков, Ukraine

Репутация: 10
Всего: 27



это потому, что CompletionHandler выполняется в асинхронном режиме, то есть в параллельном потоке. А это значит, что после вызова openWithCompletionHandler метод завершается (судя по вашему коду) и возвращает массив на текущий момент. CompletionHandler выполнится тогда, когда до него дойдет очередь
PM MAIL ICQ Skype   Вверх
cosamia
Дата 3.12.2012, 14:52 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 231
Регистрация: 11.5.2005

Репутация: нет
Всего: нет



Это я уже догадался. Но как с этим работать тогда?
PM   Вверх
Bitter
Дата 3.12.2012, 18:10 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный лентяй
***


Профиль
Группа: Завсегдатай
Сообщений: 1209
Регистрация: 15.8.2004
Где: Харьков, Ukraine

Репутация: 10
Всего: 27



Цитата(cosamia @  3.12.2012,  14:52 Найти цитируемый пост)
Но как с этим работать тогда?

Это уже вам решать
PM MAIL ICQ Skype   Вверх
cosamia
Дата 3.12.2012, 18:38 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 231
Регистрация: 11.5.2005

Репутация: нет
Всего: нет



Цитата(Bitter @ 3.12.2012,  18:10)
Цитата(cosamia @  3.12.2012,  14:52 Найти цитируемый пост)
Но как с этим работать тогда?

Это уже вам решать

Я принимаю решения на основе анализа вариантов
Для данного случая я не вижу вариантов и поэтому создал эту тему
Если вы сталкивались с такой ситуаций, то поделитесь своим вариантом
PM   Вверх
Bitter
Дата 3.12.2012, 19:22 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный лентяй
***


Профиль
Группа: Завсегдатай
Сообщений: 1209
Регистрация: 15.8.2004
Где: Харьков, Ukraine

Репутация: 10
Всего: 27



Что тут сложного? Передавайте в ваш метод блок и выполняйте его в CompletionHandler
PM MAIL ICQ Skype   Вверх
cosamia
Дата 4.12.2012, 03:18 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 231
Регистрация: 11.5.2005

Репутация: нет
Всего: нет



Цитата(Bitter @ 3.12.2012,  19:22)
Что тут сложного? Передавайте в ваш метод блок и выполняйте его в CompletionHandler

Подробнее можно что и куда передавать?

У меня есть Service класс который содержит метод 
-(NSMutableArray*)getClients;
который в свою очередь вызывает другой метод этого же класса
-(NSMutableArray*)fetchDatabaseToGetData:(UIManagedDocument *)document


Таким образом класс Service представлен в виде DAL

Теперь в контроллере мне надо вызвать этот метод что я и делаю путем

self.array = [self getClient];




PM   Вверх
Bitter
Дата 4.12.2012, 11:13 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный лентяй
***


Профиль
Группа: Завсегдатай
Сообщений: 1209
Регистрация: 15.8.2004
Где: Харьков, Ukraine

Репутация: 10
Всего: 27



Если ваш метод возвращает результаты в асинхронном режиме, то и обрабатывать их нужно в асинхронном режиме. Лучше всего для этого подходят блоки (читать про блоки тут). В блоке описываете обработку массива и передаете его (блок) в свой метод getClient.
PM MAIL ICQ Skype   Вверх
cosamia
Дата 5.12.2012, 08:14 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 231
Регистрация: 11.5.2005

Репутация: нет
Всего: нет



Цитата(Bitter @  4.12.2012,  11:13 Найти цитируемый пост)
Если ваш метод возвращает результаты в асинхронном режиме, то и обрабатывать их нужно в асинхронном режиме. Лучше всего для этого подходят блоки (читать про блоки тут). В блоке описываете обработку массива и передаете его (блок) в свой метод getClient. 


У меня нет обработки массива, я вывожу весь массив в таблицу в стандартном
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath

А перед тем как его вывести просто вызываю self.service getClientsList
где self.serivice - инстэнс класса Service

Каким образом - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath или viewDidLoad
предлагается и зачем передавать в Service.getClient??

PM   Вверх
Bitter
Дата 5.12.2012, 10:44 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный лентяй
***


Профиль
Группа: Завсегдатай
Сообщений: 1209
Регистрация: 15.8.2004
Где: Харьков, Ukraine

Репутация: 10
Всего: 27



я говорю что в метод ваш вы должны передать блок. А в блоке написать то, что вам нужно. Например [myTable reloadData];
Вы можете написать например так (добавив в ваш метод блок в качестве параметра):

[self.service getClientsWithCompletionHandler:^(id result) {
    self.clients = result;
    [myTable reloadData];
}];

блок вызываете в методе getClientsWithCompletionHandler там, где нужно (например вместо return array)
PM MAIL ICQ Skype   Вверх
cosamia
Дата 6.12.2012, 02:13 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 231
Регистрация: 11.5.2005

Репутация: нет
Всего: нет



Я пытался сделать так(до прочтения этого ответа):


[self.service  ^(id result) {
    self.clients = result;
    [myTable reloadData];
}];

В результате ничего не сработало. Не знаю это идентично предложенному или нет..

В результате проблема была решена через делегаты
PM   Вверх
Bitter
Дата 6.12.2012, 10:53 (ссылка) |    (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный лентяй
***


Профиль
Группа: Завсегдатай
Сообщений: 1209
Регистрация: 15.8.2004
Где: Харьков, Ukraine

Репутация: 10
Всего: 27



кусок кода, который вы написали - полная ерунда. Учите блоки
PM MAIL ICQ Skype   Вверх
cosamia
Дата 7.12.2012, 19:28 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 231
Регистрация: 11.5.2005

Репутация: нет
Всего: нет



 
Я точно не помню что было написано, возможно что было написано так:

self.clients= ^(something){[self.service getClients]}];

Помню что компилировалось но вылетало в рантайме
PM   Вверх
Bitter
Дата 7.12.2012, 22:56 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный лентяй
***


Профиль
Группа: Завсегдатай
Сообщений: 1209
Регистрация: 15.8.2004
Где: Харьков, Ukraine

Репутация: 10
Всего: 27



ну в любом случае, вы написали что-то вроде: присвоить блок переменной self.clients. но поскольку переменная не типа "блок", то краш.

Ну смотрите, можно было сделать так:
1. первым делом объявить тип вашего блока: typedef void (^MyCompletionHandler)(NSArray* result);
2. Метод getClient дополнить входящим параметром - блоком:

Код

-(void)getClientsWithComplitionHandler:(MyCompletionHandler)complitionHandler // тут изменение
{
    NSMutableArray *array = [[NSMutableArray alloc] init];
    if(![[NSFileManager defaultManager] fileExistsAtPath:[self.database.fileURL path]])
    {
        // return array; // это не нужно
        if (complitionHandler) {
            complitionHandler(array);
        }
    }
    else if (self.database.documentState ==UIDocumentStateClosed)
    {
        [self.database openWithCompletionHandler:^(BOOL success){
            // __block array = [self fetchDatabaseToGetData:self.database];// это не нужно
            if (complitionHandler) {
                complitionHandler([self fetchDatabaseToGetData:self.database]);
            }
        }];
        //return array; // это не нужно
    }
    else if (self.database.documentState ==UIDocumentStateNormal)
    {
       // return  [self fetchDatabaseToGetData:self.database]; // это не нужно
        if (complitionHandler) {
            complitionHandler([self fetchDatabaseToGetData:self.database]);
        }
    }
}


3. вызвать getClients передав в него блок:
Код

[self.service getClientsWithCompletionHandler:^(NSArray* result) {
    self.clients = result;
    [myTable reloadData];
}];

PM MAIL ICQ Skype   Вверх
bales
Дата 20.12.2012, 23:55 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 6
Регистрация: 19.12.2012

Репутация: нет
Всего: нет



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!
PM MAIL WWW   Вверх
Ответ в темуСоздание новой темы Создание опроса
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | iOS | Следующая тема »


 




[ Время генерации скрипта: 0.0805 ]   [ Использовано запросов: 20 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.