There are few similar questions to mine with answers,but could not find a way to use that solutions on my code. I would be glad, if anyone can help me on code. How to retry timeout request?
while block for pagination purpose:
while(mult < (int)totalCount) {
AFHTTPRequestOperation *opr = [self getRequestForAllRecordsOfClass:className updatedAfterDate:mostRecentUpdatedDate withinPage:page+1];
[pagedOperations addObject:opr];
mult = mult + PAGINATION_SIZE;
page = page + 1;
}
[[SDAFParseAPIClient sharedClient] enqueueBatchOfHTTPRequestOperations:operations progressBlock:^(NSUInteger numberOfCompletedOperations, NSUInteger totalNumberOfOperations) {
NSLog(#"totalNumberOfOperations: %u numberOfCompletedOperations: %u",totalNumberOfOperations,numberOfCompletedOperations);
} completionBlock:^(NSArray *operations) {
...
}];
and building request operation
-(AFHTTPRequestOperation *)getRequestForAllRecordsOfClass:(NSString *)className updatedAfterDate:(NSDate *)mostRecentDate withinPage:(int)page {
NSMutableURLRequest *request = [ZurmoHelper GETRequestForAllRecordsOfClass:className updatedAfterDate:mostRecentDate inPage:page];
AFHTTPRequestOperation *operation = [[SDAFParseAPIClient sharedClient] HTTPRequestOperationWithRequest:request success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"RESPONSE pagination!!! %#:", className);
NSError *error = nil; //error in parsing json
NSDictionary *jsonDict = [NSJSONSerialization JSONObjectWithData:responseObject options:kNilOptions error:&error];
if (!error) {
NSLog(#"json dict paged in : %d",page );
id dataObject = [jsonDict objectForKey:#"data"];
NSArray *itemsObject = [dataObject objectForKey:#"items"];
[self addItems:itemsObject className:className];
}
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Request for class %# failed with error: %#", className, error);
if (error.code == -1001) {
NSLog(#"for class %# page: %d,",className,page);
//need to retry this operation???
}
}];
return operation;
}
Related
I do want to test my Service that calls a method that uses AFNetworking 3.x.
Service:
+ (AnyPromise *)allRepositoriesfetchRepositoriesByLanguage:(NSString *)language forPage:(int)page {
return [[APIClient sharedClient] fetchRepositoriesByLanguage:language forPage:page].then(^(NSDictionary *response) {
NSValueTransformer *transformer = [MTLJSONAdapter arrayTransformerWithModelClass:[RepositoriesModel class]];
NSArray *repositories = [transformer transformedValue:response[#"items"]];
return repositories;
});
}
Client:
#pragma mark - fetchRepositoriesByLanguage
- (AnyPromise *)fetchRepositoriesByLanguage:(NSString *)language forPage:(int)page {
NSString *urlString = [NSString stringWithFormat:#"search/repositories?q=language:%#&sort=stars&page=%d", language, page];
return [self fetchWithURLString:urlString].then(^(NSDictionary *response){
return response;
});
}
- (AnyPromise *)fetchWithURLString:(NSString *)stringURL {
return [AnyPromise promiseWithAdapterBlock:^(PMKAdapter _Nonnull adapter) {
NSURL *URL = [NSURL URLWithString:stringURL];
[[APIClient sharedClient] GET:URL.absoluteString parameters:nil progress:nil success:^(NSURLSessionTask *task, id responseObject) {
//NSLog(#"JSON: %#", responseObject);
NSError *error;
adapter(responseObject,error);
} failure:^(NSURLSessionTask *operation, NSError *error) {
NSLog(#"Error: %#", error);
}];
}];
}
UnitTest:
it(#"should fetchRepositoriesByLanguage not be nil", ^{
id mockHTTPClient = [OCMockObject partialMockForObject:[APIClient sharedClient]];
[[[mockHTTPClient expect] andDo:^(NSInvocation *invocation) {
// we define the sucess block:
void (^thenBlock)(NSDictionary *response) = nil;
// Using NSInvocation, we get access to the concrete block function
// that has been passed in by the actual test
// the arguments for the actual method start with 2 (see NSInvocation doc)
[invocation getArgument:&thenBlock atIndex:1];
// now we invoke the successBlock with some "JSON"...:
thenBlock([NSDictionary dictionaryWithObjectsAndKeys:#"Bom Dia", #"greetings", nil]); //here I got error
}] fetchRepositoriesByLanguage:[OCMArg any] forPage:1];
[mockHTTPClient fetchRepositoriesByLanguage:#"Java" forPage:1].then(^(NSDictionary *response) {
expect(response).toNot.beNil();
});
});
But I always got an error on thenBlock, an EXC_BAD_ACCESS.
Firstly, I've added some functions which need to call from different ViewControllers in one class file. For those function, I've add SVProgressHUD as preprocess and dismiss after all process is finished. SVProgressHUD is displaying correctly before process is started. But after process, SVProgressHUD is never dismissed at all. Please let me know how to solve that issue.
I've added [SVProgressHUD dismiss]; in all process is finished. But never dismissed.
common.m
- (NSDictionary *) loadBlahClass:(NSString *)paramUserId {
[SVProgressHUD showWithStatus:#"Loading Cards..."];
__block NSDictionary *jsonResponse;
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
manager.completionQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
manager.requestSerializer = [AFJSONRequestSerializer serializer];
[manager.responseSerializer.acceptableContentTypes setByAddingObject:#"application/json"];
manager.responseSerializer = [AFHTTPResponseSerializer serializer];
NSString *urlStr = [NSString stringWithFormat:#"MY_URL"];
[manager GET:urlStr parameters:nil
success:^(AFHTTPRequestOperation *operation, id responseObject)
{
NSString *jsonString = [[NSString alloc] initWithData:responseObject encoding:NSUTF8StringEncoding];
NSData *data = [jsonString dataUsingEncoding:NSUTF8StringEncoding];
jsonResponse = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil];
[SVProgressHUD dismiss];
dispatch_semaphore_signal(semaphore);
}
failure:
^(AFHTTPRequestOperation *operation, NSError *error) {
[SVProgressHUD dismiss];
[self showAlert:APP_NAME alertMessage:[error localizedDescription]];
dispatch_semaphore_signal(semaphore);
}];
[SVProgressHUD dismiss];
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
return jsonResponse;
}
testViewController.m
_allTableData = [[NSMutableArray alloc]init];
NSDictionary *jsonResponse = [commClass loadBlahClass:strUserId];
NSNumber *status = [jsonResponse valueForKey:#"Success"];
NSString *message = [jsonResponse valueForKey:#"Message"];
NSArray *dataArray = [jsonResponse valueForKey:#"lstCC"];
if([status intValue] == 1) {
for(int i=0; i<[dataArray count]; i++) {
//working .......
}
[_ccTable reloadData];
[SVProgressHUD dismiss];
} else {
[commClass showAlert:APP_NAME alertMessage:message];
[SVProgressHUD dismiss];
}
I've found answer. Something like that.
[SVProgressHUD show];
__block BOOL result;
dispatch_async(queue, ^{
result = [self autanticate];
NSLog(#"autantication result = %d", result);
result = [self getCSRFToken];
NSLog(#"Login success result = %d", result);
dispatch_async(dispatch_get_main_queue(), ^{
[SVProgressHUD dismiss];
})
});
I am trying to redo some code to use AFNetworking. I have this method below:
-(NSArray *)GetTableDataOfPhase:(NSString *)phase
{
NSString *phaseRequestString = [NSString stringWithFormat:#"%#?jobNo=%#",kIP,phase];
NSURL *JSONURL = [NSURL URLWithString:phaseRequestString];
NSURLResponse* response = nil;
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:JSONURL];
NSData* data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:nil];
if(data == nil)
return nil;
NSError *myError;
NSArray *tableArray = [[NSArray alloc]initWithArray:[NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&myError]];
return tableArray;
}
and right now I am trying to alter it so it still returns an array, I have tried doing this:
-(NSArray *)GetTableDataOfPhase:(NSString *)phase
{
NSString *phaseRequestString = [NSString stringWithFormat:#"%#?jobNo=%#",kIP,phase];
NSURL *JSONURL = [NSURL URLWithString:phaseRequestString];
NSURLResponse* response = nil;
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:JSONURL];
AFHTTPRequestOperation *operation = [[[AFHTTPRequestOperation alloc] initWithRequest:request] autorelease];
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
NSData* data = [NSURLConnection sendSynchronousRequest:responseObject returningResponse:&response error:nil];
if(data == nil)
return nil;
NSError *myError;
NSArray *tableArray = [[NSArray alloc]initWithArray:[NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&myError]];
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
}];
[operation start];
return tableArray;
}
but I got this error:
/Users/jamessuske/Documents/My Programs/SSiPad(Device Only)ios7/SchedulingiPadApplication/Classes/LHJSonData.m:168:46: Incompatible block pointer types sending 'void *(^)(AFHTTPRequestOperation *, id)' to parameter of type 'void (^)(AFHTTPRequestOperation *, id)'
and this warning:
/Users/jamessuske/Documents/My Programs/SSiPad(Device Only)ios7/SchedulingiPadApplication/Classes/LHJSonData.m:170:97: Sending 'NSURLResponse *const *' to parameter of type 'NSURLResponse **' discards qualifiers
This is how I am calling it:
- (void)GetRequest
{
//refresh table view
[dataSource.editedCellHolder removeAllObjects];
[dataSource.cellHolder removeAllObjects];
[dataSource.cellHolderDisplay removeAllObjects];
NSArray *tableData = [dataSource.areaData GetTableDataOfPhase:[NSString stringWithFormat:#"%#%#",areaPickerSelectionString,unitPickerSelectionString]];
if(tableData == nil)
[self CustomAlert:#"Data was not recieved from the server, please check internet/VPN settings, Or contact Software Vendor for assistance."];
[dataSource PopulateTableData:tableData];
[indicatorView stopAnimating];
[indicatorView removeFromSuperview];
[loadingView removeFromSuperview];
loadingView = nil;
indicatorView =nil;
[NSTimer scheduledTimerWithTimeInterval:0.2f target:self selector:#selector(DisplayTable) userInfo:nil repeats:NO];
}
A couple of things:
Using AFNetworking, you should entirely lose the NSURLConnection request.
Likewise, the default responseSerializer does the JSON parsing for you, so you can lose the NSJSONSerialization parsing. AFNetworking does all of that for you.
Likewise, don't build URL parameters manually, but rather again let AFNetworking do that for you. By default, AFNetworking uses a requestSerializer that will build the request for you.
Your old method ran synchronously, which is generally a bad idea. Instead, you should use asynchronous patterns (e.g. a completionHandler block).
So, pulling all of this together, it probably looks like:
- (void)getTableDataOfPhase:(NSString *)phase completionHandler:(void (^)(NSArray *resultsObject, NSError *error))completionHandler
{
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
NSDictionary *parameters = #{#"jobNo" : phase};
[manager GET:kIP parameters:parameters success:^(AFHTTPRequestOperation *operation, id responseObject) {
completionHandler(responseObject, nil);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
completionHandler(nil, error);
}];
}
And you'd call it like so:
[self getTableDataOfPhase:#"..." completionHandler:^(NSArray *resultsObject, NSError *error) {
if (resultsObject) {
// use NSArray here
} else {
NSLog(#"error = %#", error);
}
}];
// but don't try to use the `resultsObject` array here!
I am trying to retrieve data using from a JSON request using AFJSONRequestOperation.
On success I am able to successfully retrieve the data but unable to complete the request and forward the data further for processing.
Following is my code
-(void) retrieveBrandList:(void (^)(NSArray *brandList))success failure:(void (^)(NSError *error))failure
{
//__block NSArray *brandList =[[NSArray alloc] init];
NSString *BrandListURL= http://127.0.0.1:8888/know/rest/brand
NSURLRequest *request = [NSURLRequest requestWithURL:url];
NSLog(#"Brand List URL = %#", BrandListURL);
AFJSONRequestOperation *operation =[AFJSONRequestOperation
JSONRequestOperationWithRequest: request
success:^(NSURLRequest *request, NSHTTPURLResponse *response, id responseObject)
{
NSLog(#"%#", responseObject);
brandList = [self successBandList:responseObject]; // parsing the JSON response in separate method (success block code)
if (success)
success(brandList);
}
failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id responseObject)
{
message:[NSString stringWithFormat:#"%#",error];
if (failure)
failure(error);
}];
[operation start];
[operation waitUntilFinished];
}
Following is the data manager to retrieve data.
- (NSArray *)getBrandList
{
#try
{
[brand retrieveBrandList:^(NSArray *brandList)
{
brands = brandList;
}
failure:^(NSError *error) {
}];
NSLog(#"Retriving Brand list completed");
return brands;
}
#catch (NSException * e) {
NSLog(#"Exception: %# , Error while getting the brand list", e);
}
return NULL;
}
How do i complete the operation and use or store the results for further processing in some other method?
id jsonObject = [NSJSONSerialization JSONObjectWithData:responseObject options:NSJSONReadingAllowFragments error:&error];
if ([jsonObject isKindOfClass:[NSDictionary class]]) {
self.jsonDictionary = jsonObject;
}
and you can check for other option too but this worked for me
At this moment I have a method that calls for the download of data from the web using AFHTTPRequestOperation like so:
- (void)downloadDataForRegisteredObjects:(BOOL)useUpdatedAtDate {
NSLog(#"downloadDataForRegisteredObjects");
NSMutableArray *operations = [NSMutableArray array];
for (NSString *className in self.registeredClassesToSync) {
NSDate *mostRecentUpdatedDate = nil;
if (useUpdatedAtDate) {
mostRecentUpdatedDate = [self mostRecentUpdatedAtDateForEntityWithName:className];
}
NSMutableURLRequest *request = [[SDAFParseAPIClient sharedClient] GETRequestForAllRecordsOfClass:className updatedAfterDate:mostRecentUpdatedDate];
AFHTTPRequestOperation *operation = [[SDAFParseAPIClient sharedClient] HTTPRequestOperationWithRequest:request success:^(AFHTTPRequestOperation *operation, id responseObject) {
if ([responseObject isKindOfClass:[NSDictionary class]]) {
// Write JSON files to disk
[self writeJSONResponse:responseObject toDiskForClassWithName:className];
}
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Request for class %# failed with error: %#", className, error);
[[NSNotificationCenter defaultCenter]
postNotificationName:kSDSyncEngineSyncINCompleteNotificationName
object:nil];
}];
[operations addObject:operation];
}
[[SDAFParseAPIClient sharedClient] enqueueBatchOfHTTPRequestOperations:operations progressBlock:^(NSUInteger numberOfCompletedOperations, NSUInteger totalNumberOfOperations) {
} completionBlock:^(NSArray *operations) {
// Process JSON into CD
if (useUpdatedAtDate) {
[self processJSONDataRecordsIntoCoreData];
}
}];
}
From what I understand, we create an NSURLMutableRequest, pass it to an AFHTTPRequestOperation with a success & failure block.
The success block says, if and when successful, test if dictionary and if so, write it to disk. The failure block says, log the error and post a notification.
The method gets called twice in my app, in series, one after the other. The first time it returns an empty responseObject but the second time it returns a full responseObject.
Why should that be the case?