objective c completion handler - objective-c

I have RequestManager class with getContentInBackgroundWithMemberId and postRequest functions. I want to call them from my view controller and get result using completion handler. How to edit my functions?
RequestManager.h
#import <Foundation/Foundation.h>
#interface RequestManager : NSObject
-(void)getContentInBackgroundWithMemberId:(int)memberId;
#end
RequestManager.m
#import "RequestManager.h"
#implementation RequestManager
-(void)postRequestWithParams:(NSDictionary*)params
{
NSString *parameters = #"encrypt=93mrLIMApU1lNM619WzZje4S9EeI4L2L";
for(id key in params)
{
NSString *obj = [NSString stringWithFormat:#"&%#=%#",key,[params objectForKey:key]];
[parameters stringByAppendingString:obj];
}
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
[request setURL:[NSURL URLWithString:#"http://someserver"]];
NSData *postBody = [parameters dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES];
[request setHTTPMethod:#"POST"];
[request setHTTPBody:postBody];
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse * _Nullable response, NSData * _Nullable data, NSError * _Nullable connectionError) {
if(!connectionError)
{
NSDictionary *serverData =[NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
NSArray *result = [NSArray array];
result = [serverData objectForKey:#"result"];
}
}];
}
-(void)getContentInBackgroundWithMemberId:(int)memberId
{
NSDictionary *params = [NSDictionary dictionary];
params = #{#"member_id":[NSNumber numberWithInt:memberId]};
[self postRequestWithParams:params];
}
#end
ViewController.h
#import <UIKit/UIKit.h>
#import "RequestManager.h"
#interface ViewController : UIViewController
#property (strong,nonatomic) RequestManager *requestManager;
#end
ViewController.m
#import "ViewController.h"
#interface ViewController
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
int memberId = 82;
//here i want to call getContentInBackgroundWithMemberId and get result using completion handler;
_requestManager = [[RequestManager alloc]init];
[_requestManager getContentInBackgroundWithMemberId:memberId];
}
#end

RequestManager.h
#interface RequestManager : NSObject
//Create a block property
typedef void(^postRequestBlock)(BOOL status);
-(void) getContentInBackgroundWithMemberId: (int) memberId completed:(postRequestBlock)completed;
#end
RequestManager.m
-(void) getContentInBackgroundWithMemberId: (int) memberId completed:(postRequestBlock)completed{
NSDictionary * params = [NSDictionary dictionary];
params = # {
# "member_id": [NSNumber numberWithInt: memberId]
};
[self postRequestWithParams: params completed:^(BOOL status){
completed(status);
}];
}
//Add completion block.
-(void) postRequestWithParams: (NSDictionary * ) params completed:(postRequestBlock)completed{
[NSURLConnection sendAsynchronousRequest: request queue: [NSOperationQueue mainQueue] completionHandler: ^ (NSURLResponse * _Nullable response, NSData * _Nullable data, NSError * _Nullable connectionError) {
if (!connectionError) {
NSDictionary * serverData = [NSJSONSerialization JSONObjectWithData: data options: 0 error: nil];
NSArray * result = [NSArray array];
result = [serverData objectForKey: # "result"];
completed(YES);
} else {
completed(NO);
}
}];
}
There are already tons of Q&A's for blocks. Here's one that might help further explain
How to write an Objective-C Completion Block

Related

Objective C variables in Async block does not change the Class variable value

I try to use my parsed JSON values from async block in other methods and viewDidLoad but, it returns the value inside the block, but in other methods it just return null
here is my Viewcontroler.m file code:
#import "ViewController.h"
#interface ViewController ()
#end
NSString *buttonText;
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self URLconnection];
NSLog(#"this is value: %#", buttonText);
}
- (void)URLconnection {
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
[request setURL:[NSURL URLWithString:#“XXXXXXXXXX"]];
NSURLSessionDataTask *task = [[self getURLSession]
dataTaskWithRequest:request completionHandler:^( NSData *data,
NSURLResponse *response, NSError *error )
{
dispatch_async( dispatch_get_main_queue(),
^{
// parse returned JSON array
NSError *jsonError;
NSArray *parsedJSONArray = [NSJSONSerialization
JSONObjectWithData:data options:NSJSONReadingMutableContainers
error:&jsonError];
NSLog( #"%#", [parsedJSONArray valueForKey:#"data" ] );
NSDictionary *dictionary = [parsedJSONArray
valueForKey:#"data"];
NSLog(#"this is dictionary %#",
dictionary[#"buttonText"]);
buttonText = dictionary[#"buttonText"];
} );
}];
[task resume];
}
#end
in the code above the NSLOG in the block return value but NSLOG in the viewDidLoad return null
Because the code in the block is executed asynchronously, it means when you are trying to print the value in the viewDidLoad() it has no value, so it is printing Null, which is right. When Block ends it's process and get's the data from the server, it will have the value in your variable and that prints the correct response.
Hope it clears.

Getting data from server in objective c class

Im trying to make a class where when I create an instance of that class and pass a username and password to the class it sends it to the server and gives whether its a valid password or whether theres an error. When I try to access the response variable from the instance I get null. I suspect that the methods begin called -(void)connectionDidFinishLoading:(NSURLConnection *)connection is happening before the variable is being accessed. Is there a better way to access the variable or call the method so it happens before the variable is accessed
Login View Controller.h
#interface LoginViewController : UIViewController
-(IBAction)Login:(id)sender;
#property (nonatomic, retain) IBOutlet UITextField *username;
#property (nonatomic, retain) IBOutlet UITextField *password;
#end
Login View Controller.m
#import "LoginViewController.h"
#import "Users.h"
#interface LoginViewController ()
#end
#implementation LoginViewController
#synthesize username, password;
/*
-(IBAction)Login:(id)sender{
Users *user = [[Users alloc] init];
[user Login:username.text :password.text];
if ([user.serverResponse isEqual: #"Status:Created"]) {
[self performSegueWithIdentifier:#"home" sender:nil];
}
else{
UIAlertView *alert = [[UIAlertView alloc]
initWithTitle:#""
message:#"Username or Password is incorrect"
delegate:self
cancelButtonTitle:#"Cancel"
otherButtonTitles:#"OK", nil];
[alert show];
}
NSLog(#"%#",user.serverResponse);
}
#end
Users Class.h
#import <Foundation/Foundation.h>
#interface Users : NSObject
- (void)Login:(NSString*)username :(NSString*)password;
- (void)Signup:(NSString*)username :(NSString*)password :(NSString*)password_confirmation :(NSString*)email;
#property (nonatomic, retain) NSMutableData *response;
#property (nonatomic, retain) NSString *serverResponse;
#end
Users Class.m
#import "Users.h"
#define loginURL #"linktoserver"
#define signupURL #"linktoserver"
#implementation Users
#synthesize response, serverResponse;
- (void)Login:(NSString*)username :(NSString*)password{
NSMutableData *data = [[NSMutableData alloc] init];
self.response = data;
NSURL *url = [NSURL URLWithString:loginURL];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[url standardizedURL]];
// Http Method
[request setHTTPMethod:#"POST"];
// Intializes Post Data
NSString *postData = [NSString stringWithFormat:#"username=%#&password=%#", username, password];
NSString *postLength = [NSString stringWithFormat:#"%lu", (unsigned long)[postData length]];
[request setValue:postLength forHTTPHeaderField:#"Content-Length"];
[request setValue:#"application/json" forHTTPHeaderField:#"Accept"];
[request setValue:#"application/x-www-form-urlencoded" forHTTPHeaderField:#"Content-Type"];
[request setHTTPBody:[postData dataUsingEncoding:NSUTF8StringEncoding]];
// Intializes Connection Request
NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
[connection start];
}
#pragma Connection
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData*)data
{
[response appendData:data];
}
-(void)connectionDidFinishLoading:(NSURLConnection *)connection{
serverResponse = [[NSString alloc] initWithData:response
encoding:NSUTF8StringEncoding];
}
Use NSURLSession instead of NSURLConnection with delegates (to simplify the process):
[[[NSURLSession sharedSession] dataTaskWithRequest:request
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
if (!error && data){ // here you can check also response.statusCode if needed
NSString *serverResponse = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
dispatch_async(dispatch_get_main_queue(), ^{
completion(serverResponse);
});
}else {
dispatch_async(dispatch_get_main_queue(), ^{
completion(nil);
//show some alert about no connection etc
});
}
}] resume];
add completion to your method
- (void) login:(NSString*)username
password:(NSString*)password
completion:(void (^)(NSSring *response))completion
and then compare response in the completion in the loginViewController
[user login:#"aaa" password:#"bbb" completion:^(NSString *response) {
if ([response isEqualToString:#"ccc"]){
// success!
}else{
// alert
}
};

Weird NSZombie error in nsmutuablearray

I had faced a weird error for a few days ago. Luckly, i had solved this error about in 4-5 day. However, i just wonder that the error why happen.
First of all, i will describe the situation with same sample of code.
#interface SampleViewController ()
#property (nonatomic, strong) NSMutableArray *selectedIssue;
#property (nonatomic, strong) NSOperationQueue *queueJSON;
#property (nonatomic, strong) NSOperationQueue *queueImage;
#end
#implementation SampleViewController
/** blah blah blah*/
- (void) fillIssueArrayMethodWithIssueId:(NSInteger) selectedId {
NSString *requestURL = [NSString stringWithFormat:#"%#Issues/Get/?id=%d", kAPIRootURL, selectedId];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:requestURL]
cachePolicy:NSURLRequestReloadIgnoringLocalCacheData
timeoutInterval:kNetworkTimeOut];
AFHTTPRequestOperation *op = [[AFHTTPRequestOperation alloc] initWithRequest:request];
op.responseSerializer = [AFJSONResponseSerializer serializer];
[op setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id response) {
NSData *JSONData = [NSData dataWithContentsOfFile:filePath
options:NSDataReadingMappedIfSafe
error:nil];
NSMutableArray *responseObject = [NSJSONSerialization JSONObjectWithData:JSONData
options:NSJSONReadingMutableContainers
error:nil];
if(responseObject) {
if([responseObject isKindOfClass:[NSArray class]]) {
_selectedIssue = [NSMutableArray arrayWithArray:responseObject];
}
}
} failure:^(AFHTTPRequestOperation *operation, NSError *error) { }];
[_queueJSON addOperation:op];
}
-(void)startDownloadImages {
NSArray *objPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *strPath = [objPaths lastObject];
if(!_queueImage)
_queueImage = [[NSOperationQueue alloc] init];
_queueImage.maxConcurrentOperationCount = 3;
NSBlockOperation *completionOperation = [NSBlockOperation new];
for (__block NSDictionary *object in _selectedIssue) {
// Photos
NSString *imgURL = object[#"ImageUrl"];
NSString *strImageFile = [NSString stringWithFormat:#"%#_%#", object[#"Id"], [imgURL lastPathComponent]];
__block NSString *strImagePath = [NSString stringWithFormat:#"%#/Images/Issues/%#", strPath, strImageFile];
NSURLRequest *request4Images = [NSURLRequest requestWithURL:[NSURL URLWithString:imgURL]];
AFHTTPRequestOperation *operation4Images = [[AFHTTPRequestOperation alloc] initWithRequest:request4Images];
[operation4Images setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id rawResult) {
BOOL isImageWrited = [rawResult writeToFile:strImagePath options:NSDataWritingAtomic error:nil];
if(isImageWrited) {
NSLog(#"Image Write Success : %#", operation.request.URL);
} else {
NSLog(#"Image Write Error: %#", imageWriteError.description);
}
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Image Write Failed : %# : %ld", operation.request.URL, (long)operation.response.statusCode);
}];
[completionOperation addDependency:operation4Images];
}
[_queueImage addOperations:completionOperation.dependencies waitUntilFinished:NO];
[_queueImage addOperation:completionOperation];
}
#end
Here is problem;
In application lifecycle, fillIssueArrayMethodWithIssueId method get JSON data to mutuablearray first. Then start to download images by getting image URL from the array.
Each second time, i want to access the _selectedIssue in fillIssueArrayMethodWithIssueId method, my app got crash (SIGSEGV)
In according to long investigation, _selectedUssue become instantly zombie object when StartDownloadImages method finished. However in this method i have never reallocated this array. I have just read values in this array. I am sure that the array become zombie object in this method so the issue fixed when removed "__block" in for loop.
So the question, __block type how could affect the _selectedIssue arrays object ?
I just want to know what i am missing...
By the way,i have been tried in StartDownloadImages method before the for loop, i had create temporary array and this temp array just initiated with _selectedIssue mutableCopy or just copy. However, i again faced with zombie problem.

capture a variable content and pass it to a second view controller

I have read so much on the subject of passing variable between ViewController in Xcode I am totally lost.
1:I have a members database on my server which is populated with members details
2: In xcode a have a "ViewController.h and .m" which run code allowing users to authenticate with the members data table on my sever. This works perfectly well, no issues.
What I want to do is capture the "login" and "password" into two variables and use the variables in a second "ViewController".
First ViewController.h:
#interface FirstViewController : UIViewController {
UITextField *txtUsername;
UITextField *txtPassword;
}
#property (nonatomic, retain) IBOutlet UITextField *txtUsername;
#property (nonatomic, retain) IBOutlet UITextField *txtPassword;
- (IBAction)loginClicked:(id)sender;
- (IBAction)backgroundClick:(id)sender;
First ViewController.m
#import "FirstViewController.h"
#import "WebViewController.h"
#import "SBJson.h"
#implementation FirstViewController
#synthesize txtPassword, txtUsername;
- (IBAction)loginClicked:(id)sender {
#try {
if([[txtUsername text] isEqualToString:#""] || [[txtPassword text] isEqualToString:#""] ) {
[self alertStatus:#"Please enter both Username and Password" :#"Login Failed!"];
} else {
NSString *post =[[NSString alloc] initWithFormat:#"login=%#&pass=%#",[txtUsername text],[txtPassword text]];
NSLog(#"PostData: %#",post);
NSURL *url=[NSURL URLWithString:#"http://www.mydomain.com/check1.php"];
NSData *postData = [post dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES];
NSString *postLength = [NSString stringWithFormat:#"%d", [postData length]];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
[request setURL:url];
[request setHTTPMethod:#"POST"];
[request setValue:postLength forHTTPHeaderField:#"Content-Length"];
[request setValue:#"application/json" forHTTPHeaderField:#"Accept"];
[request setValue:#"application/x-www-form-urlencoded" forHTTPHeaderField:#"Content-Type"];
[request setHTTPBody:postData];
//[NSURLRequest setAllowsAnyHTTPSCertificate:YES forHost:[url host]];
NSError *error = [[NSError alloc] init];
NSHTTPURLResponse *response = nil;
NSData *urlData=[NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
NSLog(#"Response code: %d", [response statusCode]);
if ([response statusCode] >=200 && [response statusCode] <300)
{
NSString *responseData = [[NSString alloc]initWithData:urlData encoding:NSUTF8StringEncoding];
NSLog(#"Response ==> %#", responseData);
SBJsonParser *jsonParser = [SBJsonParser new];
NSDictionary *jsonData = (NSDictionary *) [jsonParser objectWithString:responseData error:nil];
NSLog(#"%#",jsonData);
NSInteger success = [(NSNumber *) [jsonData objectForKey:#"success"] integerValue];
NSLog(#"%d",success);
if(success == 1)
{
//NSLog(#"Login SUCCESS");
//[self alertStatus:#"Logged in Successfully." :#"Login Success!"];
WebViewController *second = [[WebViewController alloc] initWithNibName:nil bundle:nil];
[self presentModalViewController:second animated:YES];
} else {
NSString *error_msg = (NSString *) [jsonData objectForKey:#"error_message"];
[self alertStatus:error_msg :#"Login Failed!"];
}
} else {
if (error) NSLog(#"Error: %#", error);
[self alertStatus:#"Connection Failed" :#"Login Failed!"];
}
}
}
#catch (NSException * e) {
NSLog(#"Exception: %#", e);
[self alertStatus:#"Login Failed." :#"Login Failed!"];
}
}
Second ViewController.h
#interface LettoWebViewController : UIViewController {
IBOutlet UIWebView *lettoWebView;
NSString *AmemberUsername;
NSString *AmemberPassword;
}
#property (retain) NSString *AmemberUsername;
#property (retain) NSString *AmemberPassword;
Second ViewController.m
#import "WebViewController.h"
#import "SBJson.h"
#interface WebViewController ()
#end
#implementation WebViewController
#synthesize AmemberPassword, AmemberUsername;
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
NSString *post =[[NSString alloc] initWithFormat:#"login=%#&pass=%#",[AmemberUsername text],[AmemberPassword text]];
NSLog(#"PostData: %#",post);
NSURL *myURL=[NSURL URLWithString:#"http://www.mydomain.com/apps/index.php"];
NSData *postData = [post dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES];
NSString *postLength = [NSString stringWithFormat:#"%d", [postData length]];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
[request setURL:myURL];
[request setHTTPMethod:#"POST"];
[request setValue:postLength forHTTPHeaderField:#"Content-Length"];
[request setValue:#"application/json" forHTTPHeaderField:#"Accept"];
[request setValue:#"application/x-www-form-urlencoded" forHTTPHeaderField:#"Content-Type"];
[request setHTTPBody:postData];
[lettoWebView loadRequest:request];
}
My questions is; how can I can I pass the two variables in the most simple way.
Any help would be great but please be kind I am very new to xcode and coding in general.
Regards
DJ
The solution:
When you created WebViewController, you just had to set the two parameters.
WebViewController *second = [[WebViewController alloc] initWithNibName:nil bundle:nil];
[second setAmemberUsername:[txtUsername text]];
[second setAmemberPassword:[txtPassword text]];
[self presentModalViewController:second animated:YES];
In your viewDidLoad of the WebViewController:
There was an issue, you wrote:
NSString *post =[[NSString alloc] initWithFormat:#"login=%#&pass=%#",[AmemberUsername text],[AmemberPassword text]];
But, AmemberPassword and AmemberUserName are NSString. So they don't know the text method. They aren's UITextField.
So the correction is:
NSString *post =[[NSString alloc] initWithFormat:#"login=%#&pass=%#",AmemberUsername,AmemberPassword];

How to get all records From CoreData Base using NSManagedObjectSubClass?

I am trying to implement CoreData in ios Application,Now I want to Fetch all records from Entity MUSTHAFA
My NSManagedObjectedSubClass is MUSTAHFA
MUSTHAFA.m
#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>
#interface MUSTHAFA : NSManagedObject {
#private
}
#property (nonatomic, retain) NSString * FirstName;
#property (nonatomic, retain) NSNumber * Age;
#property (nonatomic, retain) NSString * Location;
#property (nonatomic, retain) NSString * LastName;
#end
#import "MUSTHAFA.h"
#implementation MUSTHAFA
#dynamic FirstName;
#dynamic Age;
#dynamic Location;
#dynamic LastName;
#end
Adding Records to Core Data
-(void)AddRecordToCoreData{
//NSLog(#"______ ADD Core Data Implementaion");
MUSTHAFA *event = (MUSTHAFA *)[NSEntityDescription insertNewObjectForEntityForName:#"MUSTHAFA" inManagedObjectContext:managedObjectContext];
[event setLastName:#"JOHN"];
[event setFirstName:#"JOSE "];
[event setLocation:#"IDUKKI "];
[event setAge:[NSNumber numberWithInt:25]];
NSError *error;
if (![managedObjectContext save:&error])
{
NSLog(#"Error..%#",error);
}
else
{
NSLog(#"Data added to MUSTHAFA ");
}
}
Retrieving all Values from Core Data just like select * from dbTable;
-(void)FetchRecordFromCoreData:(id)data1{
//NSLog(#"______ Fetch Core Data Implementaion");
MUSTHAFA *event = (MUSTHAFA *)[NSEntityDescription insertNewObjectForEntityForName:#"MUSTHAFA" inManagedObjectContext:managedObjectContext];
//USING event how can fetch all record from Data base;
}
USING event (Instance of MUSTAHFA) how can fetch all record from Data base?
NSManagedObjectContext *context = //Get it from AppDelegate
NSFetchRequest *request = [[NSFetchRequest alloc]initWithEntityName:#"MUSTHAFA"];
NSError *error = nil;
NSArray *results = [context executeFetchRequest:request error:&error];
if (error != nil) {
//Deal with failure
}
else {
//Deal with success
}
[request release];
AppDelegate *delegate = [UIApplication sharedApplication].delegate;
NSManagedObjectContext *context =[delegate managedObjectContext];
NSFetchRequest *request = [[NSFetchRequest alloc]initWithEntityName:#"Channels"];
NSError *error = nil;
NSArray *results = [context executeFetchRequest:request error:&error];
ChannelDBArray=[[NSMutableArray alloc]init];
for (NSManagedObject *obj in results) {
NSArray *keys = [[[obj entity] attributesByName] allKeys];
NSDictionary *dictionary = [obj dictionaryWithValuesForKeys:keys];
}
if (error != nil) {
//Deal with failure
}
else {
//Deal with success
}