Objective-C issue with connectionDidFinishLoading and Delegate - objective-c

Am trying to use an API class to fetch data from a URL and then have that data returned to a method inside the ViewController. I have the ViewController call the API method.
Have tried several places on SO already and come up with the following, but it is not working and as an Objective-C noobie have tried reading documentation and such but still not understanding what could be going wrong.
I have a viewcontroller calling an method 'fetch' inside a class 'api'.
I have the connection delegates inside api class and it works ok (correct data is printed inside connectionDidFinishLoading method).
I need a delegate to return the data to a method inside the viewcontroller class.
So far I have
ViewController.h
#import "Api.h"
#interface ViewController : UIViewController <apiDelegate>{
}
- (void)apiSucceeded:(NSString *)jsonString;
- (void)apiFailed:(NSString *)failedMessage;
#end
ViewController.m
#import "ViewController.h"
#import "Api.h"
- (void)apiSucceeded:(NSString *)jsonString {
NSLog(#"WORKED");
}
- (void)apiFailed:(NSString *)failedMessage {
NSLog(#"FAILED");
}
- (void)viewDidLoad {
[super viewDidLoad];
Api* myapi = [[Api alloc]init];
[myapi fetch];
}
#end
Api.h
#protocol apiDelegate
#required
- (void)apiSucceeded:(NSString *)jsonString;
- (void)apiFailed:(NSString *)failedMessage;
#end
#interface Api : NSObject {
id _delegate;
}
#property (nonatomic, assign) id _delegate;
-(void)fetch;
#end
Api.m
#import "Api.h"
#import "ViewController.h"
#synthesize _delegate;
- (void)fetch{
//connection setup....
[NSURLConnection connectionWithRequest:[request autorelease] delegate:self];
}
-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
[self.receivedData setLength: 0];
}
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
// NSLog(#"append data");
[self.receivedData appendData:data];
// NSLog(#"Bytes: %d", [receivedData length]);
}
-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
//TODO error handling for connection
if ([_delegate respondsToSelector:#selector(apiFailed:)]) {
[_delegate apiFailed:[error localizedDescription]];
}
NSLog(#"Cannot Connect");
}
-(void)connectionDidFinishLoading:(NSURLConnection *)connection
{
NSLog(#"DONE. Received Bytes: %d", [self.receivedData length]);
NSString *jsonString = [[NSString alloc] initWithBytes: [receivedData mutableBytes] length:[receivedData length] encoding:NSUTF8StringEncoding];
if ([_delegate respondsToSelector:#selector(apiSucceeded:)]) {
[_delegate apiSucceeded:jsonString];
}
}
#end
There is no error but it just does not run 'apiSucceeded' method.
Please dont misunderstand this as a question regarding 'connectionDidFinishLoading'. That bit works well, its the handing of the data BACK to a ViewController that is causing issues.
Can anybody see what I have done wrong please?

I seems that you forgot to set
myapi.delegate = self;
after
Api* myapi = [[Api alloc]init];

Related

use of undeclared identifier

I am new to Objective-C coding ,please bear with me to ask if this is simple question
My Header file:
#import <Cocoa/Cocoa.h>
#interface AppDelegate : NSObject <NSApplicationDelegate>
#property (assign) IBOutlet NSWindow *window;
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification;
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse*) response;
#end
My Implementation file:
#import "AppDelegate.h"
#implementation AppDelegate
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
// Insert code here to initialize your application
NSMutableData *receivedData =[NSMutableData dataWithCapacity: 0];
// Create the request
NSURLRequest *theRequest=[NSURLRequest requestWithURL:[NSURL URLWithString:#"http://www.apple.com/"] cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:60.0];
// Create the NSMutableData to hold the received data.
// receivedData is an instance variable declared elsewhere.
receivedData = [NSMutableData dataWithCapacity: 0];
// create the connection with the request
// and start loading the data
NSURLConnection *theConnection=[[NSURLConnection alloc] initWithRequest:theRequest delegate:self];
if (!theConnection) {
// Release the receivedData object.
receivedData = nil;
// Inform the user that the connection failed.
}
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
NSMutableData *receivedData =[NSMutableData dataWithCapacity:0];
// This method is called when the server has determined that it
// has enough information to create the NSURLResponse object.
// It can be called multiple times, for example in the case of a
// redirect, so each time we reset the data.
// receivedData is an instance variable declared elsewhere.
[receivedData setLength:0];
}
#end
when i run the code at implementation appDelegate it gives warning
Method definition for connection:didRecieveResponse :not found
and where
-(void)connection line it gives "use of undelcared identifier connection did u mean Collection".
You do not need to declare the method
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse*) response;
in your header file if you are using the NSURLConnectionDataDelegate Protocol in your code. Just add the protocol in the implementation and use the methods from that protocol.

NSURLConnection returns old data although NSURLRequestReloadIgnoringLocalAndRemoteCacheData

I’ve got a serious problem. In my app I m downloading a XML-File using NSURLConnection. So far so good. But from time to time, the NSURLConnection returns an old version of the requested file although I set The cachePolicy to NSURLRequestReloadIgnoringLocalAndRemoteCacheData.
The really disgusting part of the bug is, that the connection always return the old version of the file until I active and then deactivate the airplane mode or I rebooted the device.
An other interesting fact is: When I activate Wifi and call the app to reload the file the correct and actual version of the file is returned. But after turning off Wifi the old version is retuned again.
I m really becoming desperate with this problem and hope anybody can help me?
Here is the code from my class, downloading the file:
#import "HTTPReciever.h"
#import "Constants.h"
#interface HTTPReciever ()
#property (strong, nonatomic) NSMutableData *receivedData;
#property (strong, nonatomic) NSString *directoryPath;
#property (strong, nonatomic) NSString *filename;
#property (assign, nonatomic) BOOL storeData;
#end
#implementation HTTPReciever
#synthesize receivedData = _receivedData;
#synthesize delegate = _delegate;
#synthesize directoryPath = _directoryPath;
#synthesize filename = _filename;
- (BOOL)recieveDataFromURL:(NSURL *)url
storeAtDirectoryPath:(NSString *)directoryPath
withName:(NSString *)name
{
[self setDirectoryPath:directoryPath];
[self setFilename:name];
[self setStoreData:YES];
return [self recieveDataFromURL:url];
}
- (BOOL)recieveDataFromURL:(NSURL *)url
{
NSURLRequest *theRequest = [[NSURLRequest alloc] initWithURL:url
cachePolicy:NSURLRequestReloadIgnoringLocalAndRemoteCacheData
timeoutInterval:cDefaultHTTPTimeOutInterval];
self.receivedData = nil;
self.receivedData = [[NSMutableData alloc] initWithLength:0];
NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:theRequest
delegate:self
startImmediately:NO];
if ([NSURLConnection canHandleRequest:theRequest] && connection) {
[connection start];
return YES;
} else {
return NO;
}
}
#pragma mark - NSURLConnectionDelegate protocol
- (void)connection:(NSURLConnection *)connection
didReceiveData:(NSData *)data
{
[self.receivedData appendData:data];
}
- (void)connection:(NSURLConnection *)connection
didReceiveResponse:(NSURLResponse *)response
{
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
[self.receivedData setLength:0];
if ([response isKindOfClass:[NSHTTPURLResponse self]]) {
NSDictionary *headers = [(NSHTTPURLResponse *)response allHeaderFields];
NSString *modified = [headers objectForKey:#"Last-Modified"];
if (modified) {
// not yet used
}
}
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
if (self.storeData) {
[[NSFileManager defaultManager] createDirectoryAtPath:self.directoryPath
withIntermediateDirectories:YES
attributes:nil
error:nil];
[self.receivedData writeToFile:[NSString stringWithFormat:#"%#%#", self.directoryPath, self.filename]
atomically:YES];
}
[self.delegate receiver:self
didFinishLoadingData:self.receivedData
lastVersion:YES];
}
- (void)connection:(NSURLConnection *)connection
didFailWithError:(NSError *)error
{
[self.delegate receiverFailedLoadingData:self];
}
- (NSCachedURLResponse *)connection:(NSURLConnection *)connection
willCacheResponse:(NSCachedURLResponse *)cachedResponse
{
return nil;
}
#end

Getting the NSURLConnection delegate callback into the right thread

I can't seem to get a Delegate callback to work when I thread my code. I am trying to call a remote server using NSURLConnection to get an access_token. The access_token is received in connection:didReceiveResponse: delegate. This is not a problem until I thread it. I thought I was passing the correct objects for my delegates, but it does not reach connection:didReceiveResponse:
Can anyone see why connection:didReceiveResponse: in LoginViewController does not get called when I thread the call? Thanks.
LoginViewController.m
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
NSString *access_token = [self getTokenFromResponse: response];
[self.delegate didGetAccessToken:access_token];
}
- (void)fetchAccessTokenNoUI
{
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString: #"www.mysite.com"]];
[NSURLConnection connectionWithRequest:request delegate:self];
}
AccessToken.h
#interface AccessToken : NSObject
#property (atomic, strong) LoginViewController *loginViewController; // doing this to try to keep it persistent
- (void) fetchAccessTokenWithDelegate: (id <LoginDelegate>)delegate;
#end
AccessToken.m
- (void) fetchAccessTokenWithDelegate: (id < LoginDelegate >)delegate
{
dispatch_queue_t downloadQueue = dispatch_queue_create("Fetch access_token queue", NULL);
dispatch_async(downloadQueue, ^ {
// this works fine if I don't do it in a queue
self.loginViewController = [[LoginViewController alloc] init];
self.loginViewController.delegate = delegate;
[self.loginViewController fetchAccessTokenNoUI];
});
dispatch_release(downloadQueue);
}
CallingClass.m
- (void)didGetAccessToken:(NSString *)access_token
{
if (!access_token)
{
LoginViewController *userProfileViewController = [[LoginViewController alloc] init];
userProfileViewController.delegate = self;
[self.navigationController pushViewController:userProfileViewController animated:YES];
}
}
- (IBAction)favourite:(id)sender
{
AccessToken *accessToken = [[AccessToken alloc] init];
[accessToken fetchAccessTokenWithDelegate:self];
}
So after some more research, I found the solution.
I don't actually need AccessToken.h/m. I thought that the NSURLConnection call would block my UI thread. But NSURLConnection connectionWithRequest:delegate: is automatically run in a separate thread.
So all I have to do is delete AccessToken.h and AccessToken.m. Then, in CallingClass.m, I change favourte: to
- (IBAction)favourite:(id)sender
{
LoginViewController *loginViewController = [[LoginViewController alloc] init];
[loginViewController fetchAccessTokenWithDelegate:self];
}
That's it! Don't need to dispatch_queue_t at all.
Have you put stubs to implement the required protocol methods,
-(void)connectionDidFinishLoading:(NSURLConnection *)connection;
-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error;
-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data;
Because I had a similar problem which went away after implementing them.

Why is Xcode saying my class implementation is incomplete?

I have created a singleton for my MusicBackground. And I receive a line code of imcomplete implementation of this line #implementation MyBgMusic. Can anyone tell me why ? Below is the code:
#import "MyBgMusic.h"
static MyBgMusic *sharedMyManager = nil;
#implementation MyBgMusic
#synthesize player,playBgMusic;
#pragma mark -
#pragma mark Singleton Methods
+ (MyBgMusic*)sharedInstance {
static MyBgMusic *_sharedInstance;
if(!_sharedInstance) {
static dispatch_once_t oncePredicate;
dispatch_once(&oncePredicate, ^{
_sharedInstance = [[super allocWithZone:nil] init];
});
}
return _sharedInstance;
}
+ (id)allocWithZone:(NSZone *)zone {
return [self sharedInstance];
}
- (id)copyWithZone:(NSZone *)zone {
return self;
}
#if (!__has_feature(objc_arc))
- (id)retain {
return self;
}
- (unsigned)retainCount {
return UINT_MAX; //denotes an object that cannot be released
}
- (id)autorelease {
return self;
}
- (void)dealloc
{
[MyBgMusic release];
[playBgMusic release];
[player release];
[super dealloc];
}
#endif
#pragma mark -
#pragma mark Custom Methods
- (void)viewDidLoad
{
NSString *path = [[NSBundle mainBundle] pathForResource:#"music" ofType:#"mp3"];
self.player=[[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:path] error:NULL];
player.delegate = self;
[player play];
player.numberOfLoops = -1;
[super viewDidLoad];
}
#end
For the M file, below is the code:
#import <Foundation/Foundation.h>
#import <AVFoundation/AVAudioPlayer.h>
#interface MyBgMusic : UIViewController <AVAudioPlayerDelegate> {
AVAudioPlayer *player;
UIButton *playBgMusic;
}
#property (nonatomic, retain) IBOutlet AVAudioPlayer *player;
#property (nonatomic, retain) IBOutlet UIButton *playBgMusic;
+ (id)sharedManager;
-(IBAction) toggleMusic;
#end
And how do I reference to my toggle button: Below is the code :
- (IBAction)toggleMusic {
if ([self.player isPlaying] == YES) {
[self.player stop];
} else {
[self.player play];
}
self.playBgMusic.enabled = YES;
}
It means that your MyBgMusic class isn't doing everything it promised to do in its header file, which includes being a UIViewController and implementing the AVAudioPlayerDelegate protocol. I'm not familiar with exactly what the AVAudioPlayerDelegate is, but it's quite possible that your class doesn't implement all of the required methods.
Also, you're declaring methods +(id)sharedManager and -(IBAction)toggleMusic, but I don't see them anywhere in the implementation file. That would be a case of promising something in the header and not implementing it in the class.
It would help if you posted the actual error message.
That error means your #implementation section does not contain everything described in the #interface section.
I can see two problems.
First you need to place this code:
- (IBAction)toggleMusic {
...
}
Somewhere in between #implementation and #end.
And you also need to rename the line + (MyBgMusic*)sharedInstance to + (id)sharedManager.
EDIT:
To access the toggle music method elsewhere in your code, you would do:
[[MyBgMusic sharedManager] toggleMusic];
Your +(id)sharedManagerimplementation is called +(id)sharedInstance. Just guessing, but it seems they are supposed to do the same.

NSUrlConnection in NSThread - No delegate is executed!

I am using an NSURLConnection in an NSThread but none of the NSURLConnection's delegate methods are executed! I have a main method in my NSTread subclass and a while loop that keeps the thread active. Any help?
Sorry for all of this code but I think its the best way to describe my problem. So this is an object that does the async connection calling createConnectionWithPath:userObjectReference
#interface WSDAsyncURLConnection : NSObject
{
NSMutableData *receivedData;
NSDate *connectionTime;
NSURLConnection *connection;
id _theUserObject;
}
#property (nonatomic, retain) NSMutableData *receivedData;
#property (nonatomic, retain) NSDate *connectionTime;
#property (nonatomic, assign) NSURLConnection *connection;
- (void)createConnectionWithPath:(NSString *)thePath userObjectReference:(id)userObject;
#end
#import "WSDAsyncURLConnection.h"
#implementation WSDAsyncURLConnection
#synthesize connectionTime, receivedData, connection;
- (void) terminate
{
if (self.connection) {
[self.connection release];
self.connection = nil;
}
}
- (void) createConnectionWithPath:(NSString *)thePath userObjectReference:(id)userObject;
{
_theUserObject = userObject;
NSURLRequest *theRequest = [NSURLRequest requestWithURL:[NSURL URLWithString:thePath]
cachePolicy:NSURLRequestReloadIgnoringLocalAndRemoteCacheData timeoutInterval:60];
self.connection = [[NSURLConnection alloc] initWithRequest:theRequest delegate:self startImmediately:YES];
if (self.connection)
{
/* record the start time of the connection */
self.connectionTime = [NSDate date];
/* create an object to hold the received data */
self.receivedData = [NSMutableData data];
}
}
- (void) connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
[self.receivedData setLength:0];
}
- (void) connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
/* appends the new data to the received data */
[self.receivedData appendData:data];
}
- (void) connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
[self terminate];
}
- (void) connectionDidFinishLoading:(NSURLConnection *)connection
{
// displays the elapsed time in milliseconds
NSTimeInterval elapsedTime = [[NSDate date] timeIntervalSinceDate:self.connectionTime];
// displayes the length of data received
NSUInteger length = [self.receivedData length];
NSString* aStr = [[NSString alloc] initWithData:receivedData encoding:NSASCIIStringEncoding];
[self terminate];
[[NSNotificationCenter defaultCenter] postNotificationName:WSDAsynchURLConnectionDidFinished
object:_theUserObject
userInfo:[NSDictionary dictionaryWithObject:aStr forKey:#"urlResponseString"]];
NSLog(#"ti=%f, l=%d, response=%#", elapsedTime, length, aStr);
}
#end
This code is mostly from an apple's example project and it works fine outside an NSThread.
But when I use it in the following thread subclass no delegate method is executed !!
#implementation IncomingThread
- (void) main {
NSAutoreleasePool *poool = [[NSAutoreleasePool alloc] init];
// I start the URLConnection here ... But no delegate is executed !
[urlConn createConnectionWithPath:#"http://localhost:8888" userObjectReference:nil];
while (![self isCancelled]) {
[NSThread sleepForTimeInterval:3.];
}
[poool release];
}
- (id) init
{
self = [super init];
if (self != nil) {
urlConn = [[WSDAsyncURLConnection alloc] init];
}
return self;
}
- (void) dealloc {
NSLog(#"deallocating (%#)...", [self className]);
[urlConn release];
[super dealloc];
}
First of all: you don't need to use NSURLConnection in the separate thread. Since it is asynchronous it doesn't block the main thread.
Second: there is not processing of your connection because you always stop the execution of the thread's runloop with this peace of code:
while (![self isCancelled]) {
[NSThread sleepForTimeInterval:3.];
}
From the docs for the sleepForTimeInterval:
No run loop processing occurs while the thread is blocked.
You’re doing this the hard way. NSURLConnection does not play very nice with threads, since it needs a run loop to work. Your thread does not have a run loop and therefore the code does not work. Why not run the connection on the main thread? Or you can wrap the connection in an NSOperation, sample code here. And nowadays you also have the option to use a synchronous connection and dispatch it to a global GCD queue.
Did you remember to assign the delegate?
Something like:
self.connection.delegate = self;
Just because your class WSDAsyncURLConnection implements the delegate methods, doesn't mean they are being called.
Late but it may save others life :)
Solution link is : NSURLConnection delege methods does not work