2013-09-24 3 views
0

Я пытаюсь разработать приложение для получения данных из веб-службы для отображения в некоторых представлениях. В первой версии приложения у меня есть только один контроллер вида и один запрос GET для веб-службы (с помощью NSURLconnection): все методы NSURLconnection находятся в Viewcontroller, и все работает хорошо.NSURLсоединение в другом классе

Теперь мне нужно будет добавить другие представления и сделать некоторые другие запросы GET, поэтому я думал, что лучше всего применить шаблон MVC: в частности, я создал класс (FV_Data), где я поместил все запросы GET и управлять NSURLconnections, в то время как в каждом ViewController я вызываю метод (в классе FV_Data) для необходимого запроса GET.

Моя проблема заключается в том, как вернуть массив с данными веб-службы в ViewController, который запрашивал данные: в моих первых тестах NSURLconnection был правильно запущен, а массив (в методе connectionDidFinishLoading) заполнен данные из веб-службы, но в контроллере просмотра массив пуст.

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

Это код, который я написал (я опускаю код в методах, которые работают).

Спасибо, Corrado

FV_Data.h

#import <Foundation/Foundation.h> 

@interface FV_Data: NSObject { 

    NSMutableData *responseStatistic; 
    NSMutableData *responseGetStatus; 

    NSURLConnection *connectionStatistic; 
    NSURLConnection *connectionGetStatus; 
} 

-(NSArray *)richiediGetStatistic; 
-(NSArray *)richiediGetStatus; 


@property (nonatomic, retain) NSArray *ArrayStatistic; 
@property (nonatomic, retain) NSArray *ArrayGetStatus; 


@end 

FV_Data.m

#import "FV_Data.h" 

@implementation FV_Data 

-(id)init { 
    self = [super init]; 
    return self; 
} 

-(void)richiediGetStatistic{ 
    ... 
} 

-(void)richiediGetStatus{ 
    ... 
} 

- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response { 
... 
} 

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data { 
    ... 
} 

- (void)connectionDidFinishLoading:(NSURLConnection *)connection { 

    if(connection == connectionStatistic){ 
     NSString *responseStatisticString = [[NSString alloc] initWithData:responseStatistic encoding:NSUTF8StringEncoding]; 
     self.ArrayStatistic = [responseStatisticString componentsSeparatedByString:@","]; 
    } 

    else if(connection == connectionGetStatus){ 
     NSString *responseGetStatusString = [[NSString alloc] initWithData:responseGetStatus encoding:NSUTF8StringEncoding]; 
     self.ArrayGetStatus = [responseGetStatusString componentsSeparatedByString:@","]; 
    } 
} 

@end 

FV_Live_ViewController.h

#import <UIKit/UIKit.h> 
#import "FV_Data.h" 

@interface FV_Live_ViewController : UIViewController { 
    IBOutlet UILabel *energia; 
} 

@property (nonatomic, retain) FV_Data *PVOutputData; 

@end 

FV_Live_ViewController.m

#import "FV_Live_ViewController.h" 

@implementation FV_Live_ViewController 

-(void)viewWillAppear:(BOOL)animated{ 

    self.PVOutputData = [[FV_Data alloc] init]; 

    [self.PVOutputData richiediGetStatistic]; 

    energia.text = [self.PVOutputData.ArrayStatistic objectAtIndex:0]; 
} 

@end 
+0

Я бы посоветовал вам рассмотреть возможность принятия установленных [установленных правил использования именования] (https://developer.apple.com/library/ios/documentation/cocoa/conceptual/ProgrammingWithObjectiveC/Conventions/Conventions.html), в частности с помощью camelCase, нижняя регистр первой буквы для переменных, используя только верхние заглавные буквы для классов, не используя символы подчеркивания и т. д. – Rob

ответ

1

Ваш connectionDidFinishLoading успешно завершая загрузки, но вы, кажется, не делать ничего сообщите диспетчеру вида что-либо, чтобы обновить пользовательский интерфейс, когда выполняются запросы данных. Вы хотите это сделать, потому что процесс загрузки происходит асинхронно. Например, если вы начнете этот процесс в viewDidLoad, загрузка будет, как правило, не полностью до тех пор, пока не закончится viewDidLoad.

Необходимо предоставить некоторый механизм, с помощью которого FV_Data может сообщить FV_Live_ViewController, что запрос завершен, и в этот момент у вас будет контроллер вашего вида обновления пользовательского интерфейса с новыми данными. Два типичных подхода:

  • Реализовать свой собственный шаблон делегата протокола, достаточно традиционное решение для такого рода проблемы, с помощью которой ваша FV_Data может информировать контроллер представления, что делается запрос. См. Delegation Pattern в Компетенции ядра какао). Это аналогично методам NSURLConnectionDataDelegate, которые вы внедрили в FV_Data, но в этом случае, а не в качестве механизма для NSURLConnection, чтобы сообщить информацию FV_Data, это будет механизм для FV_Data, чтобы сообщить FV_Live_ViewController.

  • Использовать завершающие блоки, более современное решение, которое FV_Live_ViewController может сообщить FV_Data, что делать, когда запрос будет выполнен. Это аналогично тому, что вы видите в AFNetworking, или методам какао, например sendAsynchronousRequest.

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

Кроме того, я сделаю еще один шаг и второе предложение Петра о том, что вы можете использовать проверенную, существующую стороннюю структуру для управления этими запросами, например AFNetworking. A NSOperation основанный на подходах, такой как AFNetworking, обладает многочисленными преимуществами, но элегантная реализация может быть сложной (следовательно, предлагается использовать AFNetworking, которая пользуется этими преимуществами, не позволяя вам избавиться от сорняков реализации). И, к сожалению, NSURLConnection методы вроде sendAsynchronousRequest выглядят удобными, но страдают от реальных ограничений.

Мы будем рады помочь вам в любом случае, но просто предлагаем.

+0

Спасибо за подробный ответ. Я все еще немного смущен (еще много узнать о блоках, ...), но я попытаюсь изучить и реализовать это решение. – Corrado

+0

@Corrado Если вы используете AFNetworking, он использует блоки, но также делает его намного проще, чем внедрение собственного блочного решения с нуля. AFNetworking будет хорошим способом добиться некоторого комфорта при использовании блоков. После того, как вы действительно знакомы с этим шаблоном, вы можете рассмотреть возможность реализации своих собственных блочных реализаций. Удачи. Если есть что-то, что мы можем сделать, чтобы помочь, просто дайте нам знать. – Rob

-1

Похоже на то, что вы пытаетесь сделать, используя sendAsynchronousRequest:queue:completionHandler: Может быть лучше подходит, чем реализация делегата.

2

О людях ... запрос сети требуется время для завершения, так что вы должны настроить просмотр (energia.text) ПОСЛЕ connectionDidFinishLoading:
Я извиняюсь, но, кажется, вы изобретая велосипед. Если вы знаете, как блоки работают в Objective-C, я предлагаю использовать структуру AFNetworking.
Если вы не знаете, как работают блоки - читать Apple doc about blocks первый - это действительно необходимо для успешной разработки для IOS/OS X

+0

AFNetworking (или некоторый подход, основанный на операциях), безусловно, является лучшей архитектурой, чем та, которую предлагает OP. Хорошее предложение. – Rob

Смежные вопросы