OSX application freezes when try to set the value of TextView? - objective-c

I am really new to Objective-C.
First please see the code:
Here it is the property:
#property (atomic) IBOutlet NSTextView *txtResponse;
And here it is the action:
- (IBAction)sendReq:(id)sender {
#synchronized(self)
{
request *req = [[request alloc] init];
voidCallback callback = ^(NSURLResponse *resp, NSData *data, NSError *error) {
NSString *val = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
[self.txtResponse setString:val];
//NSLog(val);
};
[req setUrl:[[NSURL alloc] initWithString:#"http://foo.bar"]];
[req setCallback:callback];
[req send];
}
}
The UI freezes when I try to use [self.txtResponse setString:val];
I also tried the code without #synchronized(self)
Where is the problem?
Thanks in advance!

3rd day that I am working with objective-c and finally found the answer :)
I used the performSelectorOnMainThread and solved the problem
- (IBAction)sendReq:(id)sender {
request *req = [[request alloc] init];
voidCallback callback = ^(NSURLResponse *resp, NSData *data, NSError *error) {
NSString *val = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
[self performSelectorOnMainThread:#selector(setResponseValue:) withObject:val waitUntilDone:NO];
};
[req setUrl:[[NSURL alloc] initWithString:#"http://programming.com"]];
[req setCallback:callback];
[req send];
}
- (void)setResponseValue:(NSString *)resp
{
[self.txtResponse setString:resp];
//NSLog(resp);
}

Related

objective c invisible array out of function param request

I'm triyng to get array from server. But it doesn't work. I'm mean in the function everything is okay with my array but out of it it's null. How to fix?
for(int i=1; i<5; i++){
NSString *category = [NSString stringWithFormat:#"%d",i];
NSString *encrypt = #"encrypt=93mrLIMApU1lNM619WzZje4S9EeI4L2L";
NSString *latitude = #"latitude=32.794044";
NSString *longtitude = #"longitude=34.989571";
NSString *params = [NSString stringWithFormat:#"%#&category=%#&%#&%#&area=CENTER",
encrypt,category,latitude,longtitude];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
[request setURL:[NSURL URLWithString:#"http://admin.t-club.co.il/api/get-buissness"]];
NSData *postBody = [params 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)
{
_myDict =[NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
_tmpArray = [_myDict objectForKey:#"result"];
NSLog(#"my array %#",_tmpArray);//here array isn't null
}
}];
[_myArray addObjectsFromArray:_tmpArray];
}
NSLog(#"my array %#",_tmpArray);//here is null
It looks like what you're aiming for is to make several async requests in sequence. This can be done by adding a little abstraction.
First, a method that makes just one request and provides a dictionary in response of the parsed JSON result...
- (void)makeRequestWithParams:(NSString *)params completion:(void (^)(NSDictionary *, NSError *))completion {
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
[request setURL:[NSURL URLWithString:#"http://admin.t-club.co.il/api/get-buissness"]];
NSData *postBody = [params 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 *dictionary = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
completion(dictionary, nil);
} else {
completion(nil, connectionError);
}
}];
}
Please note that the NSURLConnnection methods have been replaced by NSSession, so this code will need to change to that soon.
Now something that calls that first method over and over. This one takes an array of request parameters as input, fills a mutable array with the dictionary results, and calls a completion block when its done...
- (void)makeManyRequestsWithParams:(NSArray *)arrayOfParams fillingArray:(NSMutableArray *)result completion:(void (^)(BOOL))completion {
if (arrayOfParams.count == 0) return completion(YES);
NSString *nextParams = arrayOfParams[0];
[self makeRequestWithParams:nextParams completion:^(NSDictionary *dictionary, NSError *error) {
if (!error && dictionary) {
[result addObject:dictionary];
NSArray *remainingParams = [arrayOfParams subarrayWithRange:NSMakeRange(1, arrayOfParams.count-1)];
[self makeManyRequestsWithParams:remainingParams fillingArray:result completion:completion];
} else {
completion(NO);
}
}];
}
Finally, your original loop's job is now limited to just assembling the parameters. Once those are in an array, call to make the requests...
- (void)test {
NSMutableArray *arrayOfParams = [NSMutableArray array];
for(int i=1; i<5; i++){
NSString *category = [NSString stringWithFormat:#"%d",i];
NSString *encrypt = #"encrypt=93mrLIMApU1lNM619WzZje4S9EeI4L2L";
NSString *latitude = #"latitude=32.794044";
NSString *longtitude = #"longitude=34.989571";
NSString *params = [NSString stringWithFormat:#"%#&category=%#&%#&%#&area=CENTER",
encrypt,category,latitude,longtitude];
[arrayOfParams addObject:params];
}
NSMutableArray *result = [NSMutableArray array];
[self makeManyRequestsWithParams:arrayOfParams fillingArray:result completion:^(BOOL success) {
if (success) {
NSLog(#"all done, result is %#", result);
} else {
NSLog(#"sadness");
}
}];
// don't expect results to be ready here. they won't be.
// see how they are logged above in the completion block?
}
NSURLConnection sendAsynchronousRequest is asynchronous meaning it will be moved to a background thread and execution will continue without waiting for the task to complete. So by the time it gets to your bottom NSLog, the request will still be processing and the value of _tmpArray will be null.
You can use sendSynchronousRequest to have the request complete before moving on.
http://codewithchris.com/tutorial-how-to-use-ios-nsurlconnection-by-example/#synchronous

Change NSURLConnection from sendSynchronousRequest to sendAsynchronousRequest? [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Questions asking for code must demonstrate a minimal understanding of the problem being solved. Include attempted solutions, why they didn't work, and the expected results. See also: Stack Overflow question checklist
Closed 9 years ago.
Improve this question
My Code for NSURLConnection with sendSynchronousRequest works fine but how can i change it to an async request? i tried a lot but nothing would work.
if the Request is empty i´ll get an empty Array with [[]] .
How can i catch it for an Alert Message?
Please help ...
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
NSString *urlString = #"http://www.xyz.at/sample.php";
NSURL *url = [NSURL URLWithString:urlString];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
[request setURL:url];
[request setHTTPMethod:#"POST"];
NSMutableData *body = [NSMutableData data];
NSString *postWerte = [NSString stringWithFormat:#"id=%#", self.textfeld.text];
[body appendData:[postWerte dataUsingEncoding:NSUTF8StringEncoding]];
[request setHTTPBody:body];
NSError *error = nil;
NSData *returnData = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:&error];
NSLog(#"Error: %#", error.description);
NSString *returnString = [[NSString alloc] initWithData:returnData encoding:NSUTF8StringEncoding];
const char *convert = [returnString UTF8String];
NSString *responseString = [NSString stringWithUTF8String:convert];
NSMutableArray *meinErgebnis = [responseString JSONValue];
NSString *cycle = #"";
NSString *kopfdaten = [NSString stringWithFormat:#"Sendungsart: %#\r\nGewicht: %# kg\r\n\r\n", [[meinErgebnis objectAtIndex:0] objectForKey:#"ParcelTypeDescription"], [[meinErgebnis objectAtIndex:0] objectForKey:#"Weight"]];
cycle = [cycle stringByAppendingString:kopfdaten];
for(int i = 1; i < meinErgebnis.count; i++)
{
NSString *myValue = [NSString stringWithFormat:#"%# PLZ: %#\r\nStatus: %#\r\n\r\n",
[[meinErgebnis objectAtIndex:i] objectForKey:#"EventTimestamp"],
[[meinErgebnis objectAtIndex:i] objectForKey:#"EventPostalCode"],
[[meinErgebnis objectAtIndex:i] objectForKey:#"ParcelEventReasonDescription"]];
cycle = [cycle stringByAppendingString:myValue];
}
self.ergebnis.text = [NSString stringWithFormat:#"%#", cycle];
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
[self.textfeld resignFirstResponder];
You could:
create an NSOperationQueue, and
call sendAsynchronousRequest, placing all of your NSData processing code inside the completion block.
Thus, instead of:
NSURLResponse *response = nil;
NSError *error = nil;
NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
// now process resulting `data`
Use:
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[NSURLConnection sendAsynchronousRequest:request queue:queue completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
// now process resulting `data`
}];
Alternatively, you could implement the NSURLConnectionDataDelegate methods. For more information on that, see the Using NSURLConnection section of the URL Loading System Programming Guide.
You say "if the request is empty": I assume you mean "if the data returned is empty". And you say it is [[]]. If that's really what you're getting, it sounds like an array with one item (which itself, is an empty array). Or is it [] (which is an empty array)? Or is it nil?
I'm going to assume that the data returned was [], an empty array.
I'd also suggest you consider using NSJSONSerialization, the built in JSON parser, but obviously you can use JSONValue if you really want.
Finally, your implementation is skipping the first entry (NSArray uses a zero-based index). I'm assuming that was unintentional.
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[NSURLConnection sendAsynchronousRequest:request queue:queue completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
if (error) {
NSLog(#"%s: sendAsynchronousRequest error: %#", __FUNCTION__, error);
return;
}
NSError *parseError;
NSArray *meinErgebnis = [NSJSONSerialization JSONObjectWithData:data options:0 error:&parseError];
if (parseError) {
NSLog(#"%s: JSONObjectWithData error: %#", __FUNCTION__, parseError);
return;
}
if ([meinErgebnis count] == 0) {
NSLog(#"%s: meinErgebnis empty", __FUNCTION__);
return;
}
for (NSDictionary *dictionary in meinErgebnis)
{
// now process each dictionary entry in meinErgebnis
}
// etc.
}];

xcode - user login from iphone to php

I have a piece of code in the .m file as below:
- (IBAction)btnLogin:(UIButton *)sender
{
NSString *strURL = [NSString stringWithFormat:#"http://www.myworkingdomain.com/fn_checkLogin2.php?name=%#&pass=%#", self.email.text, self.password.text];
// to execute php code
NSData *dataURL = [NSData dataWithContentsOfURL:[NSURL URLWithString:strURL]];
// to receive the returend value
NSString *strResult = [[[NSString alloc] initWithData:dataURL encoding:NSUTF8StringEncoding]autorelease];
if ([strResult isEqualToString:#"0"]) {
UIStoryboard *loginFailStoryBoard = [UIStoryboard storyboardWithName:#"loginFailStoryboard" bundle:nil];
UIViewController *initialFailLogin = [loginFailStoryBoard instantiateInitialViewController];
initialFailLogin.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
[self presentModalViewController:initialFailLogin animated:YES];
//NSLog(#"%#", strResult);
} else {
UIStoryboard *memberMenuBoard = [UIStoryboard storyboardWithName:#"memberMenuStoryboard" bundle:nil];
UIViewController *initialMemberMenu = [memberMenuBoard instantiateInitialViewController];
initialMemberMenu.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
[self presentModalViewController:initialMemberMenu animated:YES];
//NSLog(#"%#", strResult);
}
NSLog(#"%#", strResult);
}
#end
I am trying to determine if a person entered the right email and password and then to move on to the next view. I have the 'strResult' in my log and it shows that the php script it working correctly. It is now seems that the if..else statement that is not working due to the part [strResult isEqualToString:#"0"]
Can someone please advice where should I change to correct this so that when a member logins with the right password, he can go to the member view?
Thanks
#dan
The main thread is where all your UI elements are displayed. If you launch a connection on the main thread, your UI will become unresponsive until the connection is resolved (Unable to press buttons, unable to scroll etc...) In order to avoid that you should use another thread. There are other ways of doing it but the following code should do the trick without blocking your UI.
NSString *loginString =[NSString stringWithFormat:#"fn_checkLogin2.php?name=%#&pass=%#", self.email.text, self.password.text];
NSURL *url = [NSURL URLWithString:#"http://www.myworkingdomain.com/"];
NSMutableURLRequest *urlRequest = [NSMutableURLRequest requestWithURL:url ];
[urlRequest setTimeoutInterval:30.0f];
[urlRequest setHTTPMethod:#"POST"];
[urlRequest setHTTPBody:[loginString dataUsingEncoding:NSUTF8StringEncoding]];
NSOperationQueue *queue= [[NSOperationQueue alloc] init];
[NSURLConnection sendAsynchronousRequest:urlRequest queue:queue completionHandler:^(NSURLResponse *response, NSData *data, NSError *error){
if ([data length]>0 && error==nil) {
NSString *html = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(#"HTML = %#",html);
}
}
];
So if data is returned you can do stuff, if connection fails you can do other stuff without blocking your UI.

Get web service response data

I have made this so far. It's code that will make a json String request with an http Header. When i run this code i get no errors. But i get a Expression result unused warning. I should get a response from the web service after sending this http header.
code:
- (void)viewDidLoad
{
[super viewDidLoad];
NSString *nid = #"";
NSString *vocab = #"";
NSString *inturl = #"testoverview";
NSString *mail = #"chh#fbr.dk";
NSString *md5pw = #"4d57e7ef1b7c3f431aca424764e9d786";
NSDictionary *jsonDictionary = [NSDictionary dictionaryWithObjectsAndKeys:
nid, #"nid",
vocab, #"vocab",
inturl, #"inturl",
mail, #"mail",
md5pw, #"md5pw",nil];
NSError *error;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:jsonDictionary options:NSJSONWritingPrettyPrinted error:&error];
NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
if (!jsonData) {
NSLog(#"Got an error; %#", error);
} else if(jsonData) {
NSString *url = #"http://www.taenk.dk/services/mobile";
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:url] cachePolicy:NSURLCacheStorageAllowed timeoutInterval:30.0];
[request setValue:jsonString forHTTPHeaderField:#"X-FBR-App"];
[[NSURLConnection alloc] initWithRequest:request delegate:self]; <-- this line triggers the warning: "Expression result unused"
NSLog(#"jsonString %#", jsonString);
}
Can anybody clarify 2 things for me:
Does this trigger a response as soon as the request to the web service?
If yes, how do i print this result out?
You need to assign the result to a variable like
NSURLConnection *con = [[NSURLConnection alloc] initWithRequest:...
for later use (e.g. [con cancel];)
Then you should at least implement the delegate method connection:didFailWithError:. In the class reference I don't see the connection:didFinishLoading... anymore. Can you use the sendSynchronousRequest:returningResponse:error: instead, then you'll have the result, be it positive or negative.
This is how I retrieved the data (this version is without ARC):
- (void) connection :(NSURLConnection *)conn didReceiveData :(NSData *)data {
NSString *msg = [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding];
[self checkAutoMailReply:msg];
[msg release];
}
msg contains the pure response data, no header or such.

NSURLConnection and Blocks

My callbacks aren't being called. I'm not that familiar with dispatch_async so any thoughts? Point being, I never see a Response.
+ (void)asyncRequest:(NSURLRequest *)request
success:(void(^)(NSData *, NSURLResponse *))successBlock_
failure:(void(^)(NSData *, NSError *))failureBlock_
{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSURLResponse *response = nil;
NSError *error = nil;
NSData *data = [NSURLConnection sendSynchronousRequest:request
returningResponse:&response
error:&error];
NSString *result = [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding];
NSLog(#"-----------------result %#", result);
if (error) {
failureBlock_(data,error);
} else {
successBlock_(data,response);
}
[pool release];
});
}
Why are you implementing your own sendAsync method?
You should look into using the provided one instead, NSURLClassReference
EDIT
Assuming you're developing for OSX, not iOS. Evidently this method is not available for iOS.