Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

PPeelen

macrumors newbie
Original poster
Jan 24, 2009
6
0
Hi,

I am trying to make a delegate, but can't really get it to work.
This is my code for my fetchURLData.h:
Code:
#import <Foundation/Foundation.h>


@class fetchURLData;
@protocol fetchURLDataDelegate;

@protocol fetchURLDataDelegate<NSObject>

@optional
- (void)didFinishWithData:(NSData *)fileData;
- (void)didFailWithError:(NSError *)error;

@end

@interface fetchURLData : NSObject {
	NSString *theURL;
	NSString *theResult;
	NSMutableData *receivedData;
	
    long long bytesReceived;
    long long expectedBytes;
	
    id<fetchURLDataDelegate> delegate;
}

- (NSString *) getTheURL;
- (NSString *) getTheResult;

- (void) setUrl: (NSString *) getTheURL;
- (void) setResult: (NSString *) getTheResult;
- (void) getData;

@property (assign) id<fetchURLDataDelegate> delegate;

@end

and this is the code for my fetchURLData.m:
Code:
#import "fetchURLData.h"


@implementation fetchURLData

@synthesize delegate;

- (NSString *) getTheURL
{
	return theURL;
}

- (NSString *) getTheResult
{
	return theResult;
}

- (void) setUrl: (NSString *) getTheURL
{
	[theURL autorelease];
	theURL = [getTheURL retain];
}

- (void) setResult: (NSString *) getTheResult
{
	[theResult autorelease];
	theResult = [getTheResult retain];
}

- (void) getData
{	
	NSURLRequest *theRequest = [NSURLRequest requestWithURL:[NSURL URLWithString:theURL] 
												cachePolicy:NSURLRequestUseProtocolCachePolicy 
											timeoutInterval:60.0];
	
	NSURLConnection *theConnection = [[NSURLConnection alloc] initWithRequest:theRequest 
																	 delegate:self];
	if (theConnection) 
	{		
		receivedData=[[NSMutableData data] retain];
	} 
	else 
	{
		UIAlertView *alert = [[UIAlertView alloc] 
							  initWithTitle:@"Error" 
							  message:@"An error occured while loading your request." 
							  delegate:self 
							  cancelButtonTitle:@"Close" 
							  otherButtonTitles:nil];
		[alert show];
		[alert release];
	}
}

- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{	
    expectedBytes = [response expectedContentLength];
	[receivedData setLength:0];
}

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
	NSLog(@"Bytes: %d of %d", [receivedData length]);
	
	[receivedData appendData:data];	
}

- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
	if (self.delegate != NULL && [self.delegate respondsToSelector:@selector(didFailWithError:)]) {
		[self.delegate didFailWithError:error];
	}
	else {
		NSLog(@"Delegate doesn't repond to connector didFailWithError");
	}
	
	[connection release];

	[receivedData release];
	// inform the user
	NSLog(@"Connection failed! Error - %@ %@",
          [error localizedDescription],
          [[error userInfo] objectForKey:NSErrorFailingURLStringKey]);
}

- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
	if (self.delegate != NULL && [self.delegate respondsToSelector:@selector(didFinishWithData:)]) {
		[self.delegate didFinishWithData:receivedData];
	}
	else {
		NSLog(@"Delegate doesn't repond to connector didFinishWithData");
	}
	
    [connection release];
	
	NSLog(@"Succeeded! Received %d bytes of data",[receivedData length]);
		
	NSString *result = [[NSString alloc] initWithData:receivedData encoding:NSUTF8StringEncoding];
	theResult = result;
	
	[receivedData release];
    [connection release];
	[result release];
}

- (void) dealloc {
	[theURL release];
	[theResult release];
	[super dealloc];
}

@end

The data is retrieved but the log shows this:
2009-08-23 03:02:39.202 stationen[95324:20b] Bytes: 0 of -1073748872
2009-08-23 03:02:39.204 stationen[95324:20b] Bytes: 1223 of 0
2009-08-23 03:02:39.247 stationen[95324:20b] Bytes: 4079 of 0
2009-08-23 03:02:39.254 stationen[95324:20b] Delegate doesn't repond to connector didFinishWithData
2009-08-23 03:02:39.256 stationen[95324:20b] Succeeded! Received 5815 bytes of data

The code calling fetchURLData doesn't recieve anything:
Code:
- (void)didFinishWithData:(NSData *)fileData
{
	NSLog(@"Got some!");
}

- (void)didFailWithError:(NSError *)error
{
	NSLog(@"Got error!");
}
The log doesn't show anything

What am I doing wrong?

Best regards,
Paul Peelen
 
Did you forget to set the delegate in the code that uses that class?

Well... off course I forgot that as well. I added it, but it still issn't working:

This is the calling class "searchResults.h":
Code:
#import <UIKit/UIKit.h>
#import "fetchURLData.h"

@interface searchResults : UIViewController <fetchURLDataDelegate> {
	IBOutlet UIActivityIndicatorView *loadingIndicator;
	IBOutlet UIProgressView *progressView;
	IBOutlet UILabel *searchingText;
}

@property (nonatomic, retain) IBOutlet UIActivityIndicatorView *loadingIndicator;
@property (nonatomic, retain) IBOutlet UIProgressView *progressView;
@property (nonatomic, retain) IBOutlet UILabel *searchingText;

@end

and the code "searchResults.m":
Code:
#import "searchResults.h"

@implementation searchResults

@synthesize loadingIndicator;
@synthesize progressView;
@synthesize searchingText;

- (void)viewDidLoad {
	[self setTitle:@"Search results"];
	
	fetchURLData *fetchURL = [[fetchURLData alloc] autorelease];
	[fetchURL setUrl:@"http://www.google.com"];
	[fetchURL getData];
	
	NSLog(@"The result of my class is: %@", [fetchURL getTheResult]);
	
	[super viewDidLoad];
}

- (void)didFinishWithData:(NSData *)fileData
{
	NSLog(@"Got some!");
}

- (void)didFailWithError:(NSError *)error
{
	NSLog(@"Got error!");
}

- (void)didReceiveMemoryWarning {
	// Releases the view if it doesn't have a superview.
    [super didReceiveMemoryWarning];
	
	// Release any cached data, images, etc that aren't in use.
}

- (void)viewDidUnload {
	// Release any retained subviews of the main view.
	// e.g. self.myOutlet = nil;
}


- (void)dealloc {
    [super dealloc];
}


@end

I still have no clue
 
I still don't see you setting the delegate of fetchURL to anything. Where is the
Code:
fetchURL.delegate = <whatever>

or

Code:
[fetchURL setDelegate:<whatever>];

Simply calling alloc/init does not set the instance creating the object as the delegate.
 
I still don't see you setting the delegate of fetchURL to anything. Where is the
Code:
fetchURL.delegate = <whatever>

or

Code:
[fetchURL setDelegate:<whatever>];

Simply calling alloc/init does not set the instance creating the object as the delegate.

That makes sence... I am going to google how to use that. I am quite new to Objective-C and (as you might noticed... ) delegates.

Please do give me some good links on delegate tutorials if you have any.

Regards,
Paul Peelen
 
Delegates are actually pretty straight forward once you know how they should be used. Cocoa makes heavily use of the delegation pattern as you may have noticed. An object may have a delegate to perform some methods on the delegate object to let that object know about the state the other object is in. It may also ask the delegate object whether it should perform some action or not, or it may ask the delegate for some data the other object need.

Setting the delegate of fetchURLData to the searchResults object, the delegate property of fetchURLData will now point to the searchResults object so the searchResults object will be receiving all the delegate actions performed by the fetchURLData object.

Another problem you have now is in the creation of the fetchURLData class. You do not call -init after -alloc, so your object won't be initialized. Try the following:
Code:
fetchURLData *fetchURL = [[[fetchURLData alloc] init] autorelease];

And just like you have set the delegate to be a property of fetchURLData, you can set theResult and theURL as properties, so you don't have to define those setTheResults: methods etc. Read the Apple Documentation for more info about this subject. Good practice is not to use the 'get' prefix within get methods, the Cocoa standard just uses the variable's name itself as method name of the getter.

Good luck!
 
Delegates are actually pretty straight forward once you know how they should be used. Cocoa makes heavily use of the delegation pattern as you may have noticed. An object may have a delegate to perform some methods on the delegate object to let that object know about the state the other object is in. It may also ask the delegate object whether it should perform some action or not, or it may ask the delegate for some data the other object need.

Setting the delegate of fetchURLData to the searchResults object, the delegate property of fetchURLData will now point to the searchResults object so the searchResults object will be receiving all the delegate actions performed by the fetchURLData object.

Another problem you have now is in the creation of the fetchURLData class. You do not call -init after -alloc, so your object won't be initialized. Try the following:
Code:
fetchURLData *fetchURL = [[[fetchURLData alloc] init] autorelease];

And just like you have set the delegate to be a property of fetchURLData, you can set theResult and theURL as properties, so you don't have to define those setTheResults: methods etc. Read the Apple Documentation for more info about this subject. Good practice is not to use the 'get' prefix within get methods, the Cocoa standard just uses the variable's name itself as method name of the getter.

Good luck!

Thanks alot for your info. Earlier I tried the following code, and it worked perfect:
Code:
	fetchURL = [[fetchURLData alloc] autorelease];
	[fetchURL setDelegate:self];

I will change it with the -init part. I will most likely need to change some stuff cause I need to get data from 3 urls.
First I need to call the server, retrieve a new URL.
Then I need to call that URL and retrieve the data.
Then I need to send this data to the server for processing and retrieve a XML file with the result. So I have quite some things left to do.

Thank you all very much for your help!

Regards,
Paul Peelen
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.