Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.
OK, I have done some reading and I am actually a step further now.
This is the flow:
- I call the
Code:
[[DataAccess sharedDataAccess] startLoadingURL:[NSURL URLWithString:@"http://www.somthing.com"] withDelegate:self];
from the AppDelegate

- in the DataAccess class is the method startLoadingURL called and I have as test printed the URL out to se that it is delivered properly.

- from the startLoadingURL method are the chain of connection delegate methods called and it all ends up with the

Code:
(void)connectionDidFinishLoading:(NSURLConnection *)connection

From this method is the, in the AppDelegate

Code:
- (void) wasLoadedForURL:(NSURL *) url data:(NSData *)d

called. I have checked it all by using NSLog and I can see that all methods are called as intended.

Now the problem:
The url send to startLoadingURL in the DataAccess class is ok, but in all other methods is the url set to null... I mapped the url to the connection in the startLoadingURL method like this:

Code:
[connectionToUrl setObject:url forKey:myConnection];

And to send it back to the delegate later on in theconnectionDidFinishLoading i did the following:
Code:
NSURL *u = [connectionToUrl objectForKey:connection];

I suppose I missed something here and perhaps you could give me a hint on what it may be?

Thanks in advance!
MACloop
 
OK, I have done some reading and I am actually a step further now.
This is the flow:
- I call the
Code:
[[DataAccess sharedDataAccess] startLoadingURL:[NSURL URLWithString:@"http://www.somthing.com"] withDelegate:self];
from the AppDelegate

- in the DataAccess class is the method startLoadingURL called and I have as test printed the URL out to se that it is delivered properly.

- from the startLoadingURL method are the chain of connection delegate methods called and it all ends up with the

Code:
(void)connectionDidFinishLoading:(NSURLConnection *)connection

From this method is the, in the AppDelegate

Code:
- (void) wasLoadedForURL:(NSURL *) url data:(NSData *)d

called. I have checked it all by using NSLog and I can see that all methods are called as intended.

Now the problem:
The url send to startLoadingURL in the DataAccess class is ok, but in all other methods is the url set to null... I mapped the url to the connection in the startLoadingURL method like this:

Code:
[connectionToUrl setObject:url forKey:myConnection];

And to send it back to the delegate later on in theconnectionDidFinishLoading i did the following:
Code:
NSURL *u = [connectionToUrl objectForKey:connection];

I suppose I missed something here and perhaps you could give me a hint on what it may be?

Thanks in advance!
MACloop

It might be easiest if you post the current code...
 
It might be easiest if you post the current code...

Of course! Here it comes:

In the AppDelegate:


Code:
- (void)applicationDidFinishLaunching:(UIApplication *)application {
....

[[DataAccess sharedDataAccess] startLoadingURL:[NSURL URLWithString:@"http://www.something.com"] withDelegate:self];
	
}


- (void) wasLoadedForURL:(NSURL *) url data:(NSData *)d{//this is the callback method - what does it mean?
	NSLog(@"wasLoadedForURL");//TEST PRINT
	NSLog([NSString stringWithFormat:@"%@", url]);//TEST PRINT
	NSURL *kURLConstant = [NSURL URLWithString:@"http://www.something.com"];
	
	if([url isEqual:kURLConstant]) {
		NSLog(@"Did make a choice...");//TEST PRINT
	}
	// If we requested more than one URL check which URL it is
	// Then call whatever is required to parse/understand the data
}


in the DataAccess:
Code:
+ (DataAccess *)sharedDataAccess {
	static DataAccess *sharedDataAccess;
	@synchronized(self) {
		if(!sharedDataAccess) {
			sharedDataAccess = [[DataAccess alloc] init];
		}
	}
	return sharedDataAccess;
}


- (id)delegate {
    return delegate;	
}


- (void)setDelegate:(id)newDelegate {	
    delegate = newDelegate;
}


- (void) startLoadingURL:(NSURL *)url withDelegate:(id)del{
	[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
	[[UIApplication sharedApplication] beginIgnoringInteractionEvents];

	[self setDelegate:del];
	
	NSLog(@"startLoadingURL");//TEST PRINT
	NSLog([NSString stringWithFormat:@"%@", url]);//TEST PRINT is printing the url
	
	if ([urlToConnection objectForKey:url] != nil){
		// Rerequested to get a URL that is currently in-flight.  
		//Depending on your app you either cancel that connection and remove it from all the dictionaries
		//OR you allow a more complex model where this target and selector get added to arrays in those dictionaries...
	}
	NSURLRequest *theRequest = [NSURLRequest requestWithURL:url];
	NSURLConnection *myConnection = [[NSURLConnection alloc]initWithRequest:theRequest delegate:self]; // Create the connection
	
	[connectionToUrl setObject:url forKey:myConnection];//Setting a url with the connection as key - to get the url call object for the connection key
	[urlToConnection setObject:myConnection forKey:url];//mapping the connection to an url - to get connection call url key
	NSData *data = nil;
	[connectionToData setObject:data forKey:myConnection];//mapping data to a current connection - to get the data call the connection key
	
	[myConnection release];
}


- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data{
	theData = [connectionToData objectForKey:connection];
	[theData appendData:data];
}

- (void)connectionDidFinishLoading:(NSURLConnection *)connection{
	NSLog(@"connectionDidFinishLoading");//TEST PRINT
	NSData *d = [connectionToData objectForKey:connection];//returning the data for this current connection
	NSURL *u = [connectionToUrl objectForKey:connection];//returning the url for this current connection
	
	NSLog([NSString stringWithFormat:@"%@",u]);//TEST PRINT
	
	//data back to delegate here
	[self.delegate wasLoadedForURL:u data:d];
	[connectionToData removeObjectForKey:connection];
	[urlToConnection removeObjectForKey:connection];
}
 
Your DataAccess object does not seem to have an init method. So where is urlToConnection created?

I have done this now...what I assume is incorrect, because it still does not work. I have defined the init method like this:

Code:
+ (DataAccess *)sharedDataAccess {
	static DataAccess *sharedDataAccess;
	@synchronized(self) {
		if(!sharedDataAccess) {
			sharedDataAccess = [[DataAccess alloc] init];
		}
	}
	return sharedDataAccess;
}


Code:
- (id)init{
    if ((self = [super init])) {
		self.urlToConnection = nil;//[[NSDictionary alloc]init];
		self.connectionToUrl = nil;//[[NSDictionary alloc]init];
		self.connectionToData = nil;//[[NSDictionary alloc]init];
	 }
	 return self;
 }

Any ideas?
MACloop
 
Yes: you are setting them to nil so no Dictionary object exists to save the data into.

well, I get a crash when doing the following:
Code:
- (id)init{
    if ((self = [super init])) {	 // Custom initialization
		urlToConnection = [[NSMutableDictionary alloc]init];
		connectionToUrl = [[NSMutableDictionary alloc]init];
		connectionToData = [[NSMutableDictionary alloc]init];
	 }
	 return self;
 }

The crash is:
Code:
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[NSURLConnection copyWithZone:]: unrecognized selector sent to instance 0x3e08de0'

I do not understand this at all...

MACloop
 
Perhaps NSURLConnections can't be used as keys in dictionaries for some reason. If that's the case just key everything off the URL and do more lookups...
 
hmmm... the class being singleton means that only one object can operate on the methods in it at a time, right?
If so - is it not possible to read out the url when starting the connection, into a variable and then when sending the data back, sen the value of this variable? Or is that not good practice?
MACloop
 
Perhaps NSURLConnections can't be used as keys in dictionaries for some reason. If that's the case just key everything off the URL and do more lookups...

ok, I have removed all URL as keys for the dictionaries and use the following:
Code:
NSURLRequest *theRequest = [NSURLRequest requestWithURL:url];
	NSURLConnection *myConnection = [[NSURLConnection alloc]initWithRequest:theRequest delegate:self];
	[connectionToUrl setObject:url forKey:myConnection];
	NSData *data = nil;
	[connectionToData setObject:data forKey:myConnection];

The init of the dictionaries does not work, no matter how I define them. It seems like the NSMutableDictionary only may be initWithCapacity...? The problem with the copy from NSURL is still there when I initiate the dictionaries in the init method. Rather frustrating because I do not follow at all what this chainreaction is... :-( I would be very nice with a hint...before I give up on this. I really want to understand it but the error msg from xcode are not really informative :-(

I have defined the dictionaires like this:
Code:
	NSMutableDictionary *connectionToData;
	NSMutableDictionary *connectionToUrl;
...
}

@property (retain) NSMutableDictionary *connectionToData;
@property (retain) NSMutableDictionary *connectionToUrl;

and

Code:
@synthesize connectionToData,connectionToUrl;

//The designated initializer. Override to perform setup that is required before the view is loaded.
- (id)init{
    if ((self = [super init])) {	 // Custom initialization
		connectionToData = [[NSMutableDictionary alloc]init];
		connectionToUrl = [[NSMutableDictionary alloc]init];
	}
	 return self;
 }
 
hmmm... the class being singleton means that only one object can operate on the methods in it at a time, right?
If so - is it not possible to read out the url when starting the connection, into a variable and then when sending the data back, sen the value of this variable? Or is that not good practice?
MACloop

No. A singleton class means that there can only be one instance of it. It places no restriction on parallel use from multiple other objects or threads. Of course your code may or may not actually be thread-safe: that's for you to work out.

...

The init of the dictionaries does not work, no matter how I define them. It seems like the NSMutableDictionary only may be initWithCapacity...? The problem with the copy from NSURL is still there when I initiate the dictionaries in the init method. Rather frustrating because I do not follow at all what this chainreaction is... :-( I would be very nice with a hint...before I give up on this. I really want to understand it but the error msg from xcode are not really informative :-(

I have defined the dictionaires like this:
Code:
	NSMutableDictionary *connectionToData;
	NSMutableDictionary *connectionToUrl;
...
}

@property (retain) NSMutableDictionary *connectionToData;
@property (retain) NSMutableDictionary *connectionToUrl;

and

Code:
@synthesize connectionToData,connectionToUrl;

//The designated initializer. Override to perform setup that is required before the view is loaded.
- (id)init{
    if ((self = [super init])) {	 // Custom initialization
		connectionToData = [[NSMutableDictionary alloc]init];
		connectionToUrl = [[NSMutableDictionary alloc]init];
	}
	 return self;
 }

You should be using the accessors that you have synthesized to set the properties.
 
No. A singleton class means that there can only be one instance of it. It places no restriction on parallel use from multiple other objects or threads. Of course your code may or may not actually be thread-safe: that's for you to work out.
Ok, but if there is only one instance of the class does that not mean that it may only be used by one object? I thought so... but I suppose you can control the paralell-stuff in the AppDelegate... but that has to come late on. By now I have to solve this problem...
 
No, you are setting the variable directly.

Code:
myVar = myVal;

is not the same as

Code:
self.setMyVar(myVal);

..of course... :eek:
I did it like this now and it seem to work...
Code:
NSMutableDictionary *a = [[NSMutableDictionary alloc]init];
	[a setObject:url forKey:url];
	[self setConnectionToUrl:a];
	[a release];
...thanks for the patience...
 
No. A singleton class means that there can only be one instance of it. It places no restriction on parallel use from multiple other objects or threads. Of course your code may or may not actually be thread-safe: that's for you to work out.

By the way - I spend my time on the way home from work to think about this concurrency problem you mentioned before (see above). Let's say that my multiconnection and multiparser works allright (somewhen...). How shall I, from my AppDelegate class (or any other class later on in the program flow) call those by using multiple urls and make it thread safe? Do you have any ideas about what I could look more into in order to prepare for this? I think it being a very interesting thing to try to implement!
Thanks in advance!
MACloop
 
By the way - I spend my time on the way home from work to think about this concurrency problem you mentioned before (see above). Let's say that my multiconnection and multiparser works allright (somewhen...). How shall I, from my AppDelegate class (or any other class later on in the program flow) call those by using multiple urls and make it thread safe? Do you have any ideas about what I could look more into in order to prepare for this? I think it being a very interesting thing to try to implement!
Thanks in advance!
MACloop

It is, in general, more complex a subject that I really want to get into. The first few chapters of Java Concurrency in Practice are excellent, even for non-Java programmers. In general you need to work out what can go wrong if two threads are accessing one method at the same time and protect against that. Check the synchronized part of the code for the singleton from Apple. Why is that being done?
 
Thanks alot! To get a bit deeper into the singleton and apple is a very good beginning I think. I will look into the java link as well. I have some java experience...
Again - thanks for the advice!
MACloop
 
Code:
#import "theParser.h"

...

- (void)parsingData {
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
	self.theList = [NSMutableArray array];
	self.currentParseBatch = [NSMutableArray array];
    self.currentParsedCharacterData = [NSMutableString string];
	
    NSXMLParser *theParser = [[NSXMLParser alloc] initWithData:theData];
    [theParser setDelegate:self];
    [theParser parse];
   
	[COLOR="Red"]} // <--<<[/COLOR]
    self.currentParseBatch = nil;
    self.currentObject = nil;
    self.currentParsedCharacterData = nil;
    [theParser release];        
}

The above method has a memory leak. You allocate a new NSAutoreleasePool but never drain or release it.

You also have an unbalanced }, marked in red with // <--<<.
 
The above method has a memory leak. You allocate a new NSAutoreleasePool but never drain or release it.

You also have an unbalanced }, marked in red with // <--<<.

Thanks for you comment...but this is not the whole code...it is only parts of it to show the flow... sorry if I did not mentioned that...

MACloop
 
Hello,
I have defined a DataAccess class controlling the NSURLConnection action. The data received from this class is sent to a parser, which is parsing the data. The data is saved in an array owened by the AppDelegate. The purpose is to get the data on app-start. Most of the data in this app will only be downloaded once pro app-run. In the viewcontroller do I the following call, as I fill the tabelView with data:
Code:
theListToBeFilled = [(AppDelegate*)[[UIApplication sharedApplication] delegate] someList];

This works fine. So - now I have a structure working for one object. The thing is, I have to do this for 4 different dowloads on app-start. How do I arrange that properly? I Have read about notifications and also tried that out. I defined a notification in my parser and let my AppDelegate listen to this. When the notification was send, the userInteraction was enabled. But how to bring this on 4 files, four parsers, ...?

Any Ideas on this? What approach is the best?
Thanks in advance!
MACloop
 
(@ robbie: I tried to msg you but your inbox seems to be full)

Ok, this is how I think about the structure of my AppDelegate and it came up some questions on the way too:

Code:
@implementation MyAppDelegate 
- (void)applicationDidFinishLaunching:(UIApplication *)application
{
    // Creating and defining the navigation controller etc.

    //userinterface is not open for user interaction yet


	//save the four URLs into an array and
	//starts the DataAccess objects concurrently
	for(NSURL *myUrl in URLArray) {
		[[DataAccess sharedDataAccess] startLoadingURL:myURL withDelegate:self];
	}
}

//when the loading is done, this method is called from the DataAccess class
- (void) data:(NSData *) wasLoadedForURL:(NSURL *) url{

	if(url isEqual:[NSURL urlAsString:@"http://www.something1.com"]) {
		//create a parser for a specific kind of data
	}
	else if(url isEqual:[NSURL urlAsString:@"http://www.something2.com"]) {
		//create a parser for a specific kind of data
	}
	else if(url isEqual:[NSURL urlAsString:@"http://www.something3.com"]) {
		//create a parser for a specific kind of data
	}
	else if(url isEqual:[NSURL urlAsString:@"http://www.something4.com"]) {
		//create a parser for a specific kind of data
	}
	else {
	//perhaps error msg here
	}

}

/when the parsing is done, this method is called from the Parser class
- (void) parserDone:(NSMultableArray *) wasLoadedForURL:(NSURL *) url{
    if(the url or a key used in the parser to keep the parserResults apart is == something) {
        save the array as an local array in AppDelegate
    }
    else if(the url or a key used in the parser to keep the parserResults apart is == somethingElse) {
        save the array as an local array in AppDelegate
    }
   ...
When done 4 times - enable user interface...
}
@end

Question:
- how do I know when all four parsers are done? At this point I would like to call a method to enable the user interface. The only way I can imagine is to use a counter here. This counter is added +1 everytime the method is called and when the counter == 4, the user interface will be enabled? Or are there some more effective and reliable methods already defined by apple to solve this?

Thanks in advance!
MACloop
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.