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

spaceman816

macrumors member
Original poster
Jul 29, 2009
30
0
This is the simplified version of my problem:

.h
Code:
NSString *string;
@property ....

.m
Code:
@synthesize string;
- (void)method1 {
	//Call requester method
	NSLog(string);
}

- (void)request:(Requester*)request didLoad:(id)result {
        string = @"changed string";
}

The NSLog in method1 is called before the string is able to change in the request method. The only way i know of to make sure this happens in order is to set up a delay, but that isn't ideal or consistant.
Thanks
 
You're not properly using the string property that you defined, so it's possible that the value you assign to string in the request method is being lost.

Generally speaking, anywhere you assign a value to string you want to do

Code:
self.string = @"whatever";

to make sure that the new value is retained and the old value released.
 
You're not properly using the string property that you defined, so it's possible that the value you assign to string in the request method is being lost.

Generally speaking, anywhere you assign a value to string you want to do

Code:
self.string = @"whatever";

to make sure that the new value is retained and the old value released.

To elaborate a little bit...
Code:
string = @"some string"
Simply points the string pointer to the constant string in your application. This can cause problems if you point it to something else, for example an autoreleased NSString. Then you'll have no idea if that string is actually still in memory or not.

What I usually use are retain properties like this
Code:
@property (nonatomic, retain) NSString *string;
This way the
Code:
@synthesize string;
turns into this
Code:
- (void) setString:(NSString*)s {
    [string release];
    string = s;
    [string retain];
}
And
Code:
self.string = @"Some string"
translates to
Code:
[self setString:@"Some string"]
 
I always forget that string literals are statically allocated rather than autoreleased (although of course you should still retain and release them if necessary). I think the OP needs to post all of their real code so we can really see what is happening.

It's not clear whether string is ever initialized before the NSLog, so it is possible by chance or some optimization that it points to @"changed string" already.
 
I'm sorry I wasn't clear enough. I'll post more of my code.
I am working with the facebook api- that's not so relevant so I didn't want to confuse everything. Important lines of code are bolded:

.h:
Code:
NSString *lastLink;

Code:
@property (nonatomic, retain) NSString *lastLink;


.m:
Code:
- (void)postToWall {
	NSDictionary *params = nil;
	[B][[FBRequest requestWithDelegate:self] call:@"facebook.photos.upload" params:params dataParam:(NSData*)drawImage.image];
	NSLog(@"second test =%@",lastLink);[/B]
	FBStreamDialog* dialog = [[[FBStreamDialog alloc] init] autorelease];
	dialog.userMessagePrompt = @"Enter your message:";
	dialog.attachment = [NSString stringWithFormat:@"{\"name\":\"lorem ipsum\",\"href\":\"http://www.sample.com/\",\"caption\":\"%@\",\"description\":\"\",\"media\":[{\"type\":\"image\",\"src\":\"%@\",\"href\":\"http://www.sample.com\"}]}",
						 _facebookName, _facebookName, lastLink];	
	dialog.actionLinks = @"[{\"text\":\"lorem ipsum\",\"href\":\"http://www.sample.com/\"}]";
	[dialog show];
}

- (void)request:(FBRequest*)request didLoad:(id)result {
	if ([request.method isEqualToString:@"facebook.photos.upload"]) {
		NSDictionary* photoInfo = result;
		[B]lastLink = [photoInfo objectForKey:@"src_small"];
		NSLog(@"first test =%@",lastLink);[/B]
        }
}

This what I want to happen: When I call [[FBRequest requestWithDelegate:self] call:mad:"facebook.photos.upload"... the view loads and the didLoad method is called. lastLink changes to the correct link (and the NSLog for first test appears), and then when the NSLog is called for the second link, it has been changed already so I have the right string.

This is what actually happens: Things don't happen in the correct order. The didLoad method is called, but somehow the rest of the code in the postToWall method continues to be called either simultaneously. The result is that the NSLog for second test displays before first test, and I don't have the correct value for last link until a few seconds later.

I hope this makes sense now.
 
I'm not familiar with the FB API but it looks like your FBRequest is a wrapper for NSURLConnection. NSURLConnection works asynchronously. Meaning that you queue up a connection request and then later it calls back the various delegate methods with the results. It's not done until you get the final delegate callback.

In the code you show this appears to be the request:didLoad: method.

You need to change your design so that it doesn't move to the next step until the request:didLoad: method has been called (or the request:didntLoad method for errors). It would seem that just moving the code that shows the dialog to the request:didLoad: method would work.

You're thinking that things work synchronously but they don't work that way. And on a cell phone it's better that they don't.
 
You need to change your design so that it doesn't move to the next step until the request:didLoad: method has been called (or the request:didntLoad method for errors). .

Any tips for how to do this? The only way I can think of is with the performSelector:withObject:afterDelay: method, and it doesn't seem possible that delaying the method for a specified amount of time can be the most efficient method.
 
What's wrong with this:

Code:
- (void)postToWall {
	NSDictionary *params = nil;
	[[FBRequest requestWithDelegate:self] call:@"facebook.photos.upload" params:params dataParam:(NSData*)drawImage.image];
	NSLog(@"second test =%@",lastLink);
}

- (void)request:(FBRequest*)request didLoad:(id)result {
	if ([request.method isEqualToString:@"facebook.photos.upload"]) {
		NSDictionary* photoInfo = result;
		lastLink = [photoInfo objectForKey:@"src_small"];
		NSLog(@"first test =%@",lastLink);

	FBStreamDialog* dialog = [[[FBStreamDialog alloc] init] autorelease];
	dialog.userMessagePrompt = @"Enter your message:";
	dialog.attachment = [NSString stringWithFormat:@"{\"name\":\"lorem ipsum\",\"href\":\"http://www.sample.com/\",\"caption\":\"%@\",\"description\":\"\",\"media\":[{\"type\":\"image\",\"src\":\"%@\",\"href\":\"http://www.sample.com\"}]}",
						 _facebookName, _facebookName, lastLink];	
	dialog.actionLinks = @"[{\"text\":\"lorem ipsum\",\"href\":\"http://www.sample.com/\"}]";
	[dialog show];        }
}
 
Sorry. Don't know why I missed that, or why I didn't thing of that myself.
Thanks a lot.
 
Code:
- (void)request:(FBRequest*)request didLoad:(id)result {
	if ([request.method isEqualToString:@"facebook.photos.upload"]) {
		NSDictionary* photoInfo = result;
		[B][COLOR="Red"]lastLink[/COLOR] = [photoInfo objectForKey:@"src_small"];
		NSLog(@"first test =%@",[COLOR="DarkOrchid"]lastLink[/COLOR]);[/B]
        }
}

The code hilited in red is not using the property accessor. It's doing a direct assignment to the instance variable. One consequence of this is that a retain is not being done. This will probably prove fatal later on.

The purple code is also not using a property accessor. Here it's not as problematic.

If you're going to go to the trouble to declaring properties, then you must use them consistently. If you're not going to do that, then you're better off not declaring every ivar as being a property.

One self-defeating feature I see in this code is that your property name and ivar name are identical. This makes it harder to detect inappropriate ivar uses that ought to be property uses. The compiler always behaves as if you fully understand what you're doing and why. It doesn't have a "do the safe thing I should have written, not the unsafe thing I wrote" mode.

Avoid that by using different names for property and ivar, and establishing the correlation when the property is defined.
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.