ObjC object changes to random objects: a memory issue - iphone

long time listener, first time caller.
I have a basic memory issue I don't understand, that I'm sure just about any one of you will see in a second. I'm playing around, trying to learn various ways of using UIWebViews, getting strings from URLs, and so on. Specifically, I'm trying to obtain one URL from another. In other words, I have uploaded an html page to the web, containing a URL. The address for that page is coded into the app, giving me a "hook" into the app - I can change the contents of that page and send the app a new URL any time I want. Make sense?
So...retrieving the URL? No problem. Passing it into a string for later use - no problem. But when I set up a tap gesture recognizer, which should take that string, convert it back to an NSURL, and open it in Safari, I get a runtime crash. An NSLog call tells me that the string in question keeps being assigned to all sorts of random things.
The relevant bits of my code follow. I'm sure some of you will tell me there are much better ways to do what I want - and that's certainly welcome. But I'd also really love to know what I'm doing wrong for this particular implementation, as I'm sure it's a basic misunderstanding that I'd like to correct.
Thanks in advance. (And sorry about the formatting of the code block - haven't quite got the hang of posting on here!)
#import "Messing_With_Web_ViewsViewController.h"
#implementation Messing_With_Web_ViewsViewController
#synthesize tapView;
NSString *finalURL;
- (void)viewDidLoad {
[super viewDidLoad];
NSString *firstString = #"http://www.my_web_address.html";
//Of course, I have the correct address here.
NSURL *firstUrl = [NSURL URLWithString:firstString];
NSError * error;
finalURL = [NSString stringWithContentsOfURL:firstUrl
encoding:NSASCIIStringEncoding error:&error];
if ( finalURL )
{
NSLog(#"Text=%#", finalURL);
//everything fine up to here; console prints the correct
contents of "my web address"
}
else
{
NSLog(#"Error = %#", error);
}
//Taps
UITapGestureRecognizer *tapRecognizer;
tapRecognizer=[[UITapGestureRecognizer alloc]
initWithTarget:self
action:#selector(foundTap:)];
tapRecognizer.numberOfTapsRequired=1;
tapRecognizer.numberOfTouchesRequired=1;
[tapView addGestureRecognizer:tapRecognizer];
[tapRecognizer release];
}
- (void)foundTap:(UITapGestureRecognizer *)recognizer {
NSLog(#"Trying to load %#", finalURL);
//at this point the app either crashes, or the console shows a random memory object
[[UIApplication sharedApplication] openURL:[NSURL URLWithString: finalURL]];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
- (void)viewDidUnload {
}
- (void)dealloc {
[finalURL release];
[super dealloc];
}
#end

finalURL = [NSString stringWithContentsOfURL:firstUrl
encoding:NSASCIIStringEncoding error:&error];
The line above creates an instance of NSString which you do not own (because you did not call a method whose name includes 'new', 'alloc' 'retain', or 'copy' on it). That finalURL with therefore eventually be destroyed when it is no longer needed. By the time your -foundTap: method runs finalURL has been deallocated and you are just referencing the memory location where it used to be and which now may contain some other object or random data.
Read the memory management guidelines again and also learn to run the static analyzer which should point out mistakes like this.

Related

How do i get as NSArray from a block equal to a class data member?

- (void)viewDidLoad
{
[super viewDidLoad];
[VenueManager searchNear:#"Orlando"
onLoad:^(NSArray *objects) {
self.locationObjects = objects;
[self.tableView reloadData];
} onError:^(NSError *error) {
NSLog(#"%#", error);
}];
}
This code is in my viewDidLoad method of my UITableViewController class. It is the starting point for using RestKit to parse a JSON file from FourSquare. I was pulling my hair out because i couldn't get the objects to show up in my Table View until i put [self.tableView reloadData];. With out that call the app never even hit my - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *) because after the block was done executing locationObjects would be nil.
Before when I was debugging it the self.locationsObjects = objects worked when i was in the block (i am very unfamiliar with blocks by the way). As soon as i was out of the block the debugger would say locationObjects was nil, even though it had said it had 30 objects just like objects did when i had a break point at the assignment statement.
Can some one help me understand what is going on here.
Additional info:
Right now everything is working, or appears to be working my table is populated with the objects request from the JSON document. Originally I was doing this exact same thing in a normal ViewController and trying to set the objects from the block equal to locationObjects. Then using a prepareForSegue method i was trying to pass the locationObjects to the tableViewController in the standard method i have learned from numerous tutorials. I would get a SIGBAT error. The thread would terminate because of an unrecognized selector sent to the table view controller. Through debugging i would find that locationObjects could be nil in the prepareForSegue method. Here is the code from the viewController file.
Also I would get a warning here locationTableViewController.locationObjects = self.locationObjects; saying something about assigning a pointer of type NSArray to strong NSArray, or something like that ( i have since changed a lot attempting to get the code working and deleted some storyboard assets, so i'm not 100% sure of the wording).
#implementation CoffeeShopViewController
#synthesize venueCountLable = _venueCountLable;
#synthesize locationObjects = _locationObjects;
- (void)viewDidLoad
{
[super viewDidLoad];
[VenueManager searchNear:#"Orlando"
onLoad:^(NSArray *objects) {
self.venueCountLable.text = [NSString stringWithFormat:#"%d", objects.count];
self.locationObjects = objects;
} onError:^(NSError *error) {
NSLog(#"%#", error);
}];
}
- (void)viewDidUnload
{
[self setVenueCountLable:nil];
[super viewDidUnload];
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"locationTableSegue"])
{
LocationTableViewController *locationTableViewController = segue.destinationViewController;
locationTableViewController.locationObjects = self.locationObjects;
}
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return YES;
}
#end
Try:
#property (nonatomic, copy) NSArray *locationObjects;'
Edit on why this works:
To be honest, I really don't know the underlying reason for this to work and strong not working.
When I saw the problem, it appeared to me that strong being equivalent of retain - inserting copy instead of strong could secure that locationObjects wouldn't be nullified. Thinking again over it, I suspected that my assumption could be wrong - retain literally meant 'Do not release this object because now there is one more guy holding it.'
That, however, works somewhat differently. See this.
What Malaxeur's answer and comments below tells could possibly apply to NSArray in your example - despite strong ownership to locationObjects, what you are given is a reference to objects NSArray (an NSMutableArray*) instead of copy of it. Once out of scope (block end), it is no longer usable, and ARC claims it. Using copy in turn forces it to create another space in memory just for locationObjects, which would remain forever until you free it up.
I still do not consider this a perfect explanation as I have never understood blocks fully. I would keep this open to everyone who knows better, would fill up as soon as I get something that's useful.

RestKit Handling overlapping RKRequest Delegates

I have several RestKit gets that all use the same format:
[[RKClient sharedClient] get:endString queryParameters:params delegate:self];
I have a masterMethod that essentially refreshes all my user's restful data that looks like this
-(void)masterMethod
{
[self get1];
[self get2];
[self get3];
[self get4];
[self get5];
}
Where all the gets are in the same format as the one above. All of this code is in a class that includes the delegate method:
- (void)request:(RKRequest*)request didLoadResponse:(RKResponse*)response
However, I think something is going wrong when I try to call all give gets in the same method. It's as though the delegate didLoadResponse & didRecieveResponse methods are overlapping or getting release or something. Is there a way to make a master queue to handle this huge call? Or is something else going wrong.
I'm getting a BAD_ACCESS error somewhere in the masterMethod call.
Thanks, any help greatly appreciated.
What are you getting? If you're pulling down objects you should us the isKindOfClass method to distinguish the objects in objectLoader:didLoadObjects and set appropriately.
- (void)objectLoader:(RKObjectLoader*)objectLoader didLoadObjects:(NSArray*)objects {
if ([[objects objectAtIndex:0] isKindOfClass:[Apple class]]) {
Apple *apple = [objects objectAtIndex:0];
}
else if ([[objects objectAtIndex:0] isKindOfClass:[Banana class]]) {
Banana *banana = [objects objectAtIndex:0];
}
}
If you're pulling data from the request response, look into setting userdata on the request object, then checking the userdata in request:didLoadResponse. For more information see RestKit: distinguish multiple requests in didLoadResponse:.

instance variables not accessible

Serious Problem here... i'm getting ECX_BAD_ACCESS if i try to NSLog an instance variable of my custom object. Following Function is called in my ViewController, payload holds String Data which is pulled from a url.
- (void) initVcardWithData:(NSString *)payload {
NSLog(#"1. initVcardWithData");
aVCard = [[vcardItem alloc] initWithPayload:payload];
VCardViewController *aVCardViewController = [[VCardViewController alloc] initWithVCard:aVCard];
[self presentModalViewController:aVCardViewController animated:YES];
[aVCard release];
}
So far so good. The initWithWithVCard function is as follows, theVCard and theVCardN are defined in #implementation and also set as a #property (nonatomic, retain) in (.h).:
-(id)initWithVCard:(vcardItem *)aVCard {
if(self = [super init]) {
theVCard = [aVCard retain];
theVCardN = [theVCard.PersonName retain];
}
NSLog(#"---- vCardViewController :: initWithVcard :: FirstName: %#", theVCard.PersonName.FirstName);
return self;
}
If i access the theVCardN object in my ViewController aVCardViewController within ViewDidLoad everything works like a charm. I set some labels with data from that object.
If i then try to access the instance variables from theVCardN within a function which is called from an IBAction which is connected to a button in View, i get an EXC_BAD_ACCESS error at the debugger console. The Function which tries to pull data from the instance variables is as follows:
-(IBAction)addressbookButtonTapped {
NSLog(#"RETAIN COUNT FOR theVCard: %i", [theVCard retainCount]);
NSLog(#"RETAIN COUNT FOR theVCardN: %i", [theVCardN retainCount]);
NSLog(#"Save to Adressbook: %#", theVCardN.FirstName);
//[self dismissModalViewControllerAnimated:YES];
}
The RetainCounter for theVCardN right before calling NSLog outputs "1". The NSLog Line then returns EXC_BAD_ACCESS in Debugger Console.
Any idea ?
Do not call -retainCount. Absolute retain counts are useless.
retainCount returns the absolute retain count of an object. The actual value will be an implementation detail that is very often completely out of your control as the system frameworks may do any number of things internally to cause the retain count to be modified in ways you don't expect.
It is useless for debugging and their are a wealth of tools that are specifically focused on tracking down these kinds of issues.
First, if there is a crash, there is a backtrace. Post it. Probably not that interesting in this case, but, still, always look to the backtrace to at least confirm that it is crashing where/how you think it is.
From the evidence posted, it sounds like theVCardN.FirstName is either set to garbage or the underlying string has been over-released. Turn on zombie detection mode and see if that is the case. Since it is crashing on FirstName, then show the code related to creating/storing the FirstName.
Also, instance variables and methods should always start with a lowercase letter; PersonName should be personName & FirstName should be firstName.
Maybe i'm reading the code wrong or misunderstanding your class structure, but it looks like you logging:
NSLog(#"Save to Adressbook: %#", theVCardN.FirstName);
Above, where you say it is still working, you are logging:
theVCard.PersonName.FirstName
Are you missing the "PersonName"? Meaning you should be logging:
NSLog(#"Save to Adressbook: %#", theVCardN.PersonName.FirstName);

Iphone application. Crash without the self keyword

I will try to make myself as clear as possible. Let start from the beginning. I have an application with a tableview that contains a list of places with distances from myLocation. Now everytime I get an update in the gps location I run the following code
- (void)locationUpdate:(CLLocation *)location {
myLocation = location;
for (Trek * trek in list) {
CLLocation *loc = [[CLLocation alloc] initWithLatitude:[trek latitude_start] longitude:[trek longitude_start]];
double dis = [locationManager getDistance: loc];
[trek setDistance:dis];
[trek setDistanceUnit];
[loc release];
}
[self.tableView reloadData];
}
Now this piece of code [trek setDistanceUnit]; calls
-(void) setDistanceUnit {
if (self.distance < 1000.0)
self.distanceString = [NSString stringWithFormat:#"%.0lf m", self.distance];
}
Now if I use only distanceString the application crash. Now I think it may have something to do with the fact that those updates may run concurrently (in parallel) to the access required by the view to draw the cells. Anyone has any idea? I can post more code if helpful, I just didn't want to post too much to make this post too long.
I tried to search everywhere but I could not found anything so far.
Thanks in advance,
Umberto
PS Now the application is working but I would like to understand what is going on.
If your distanceString is a retain property, assigning it without self sets it up for a crash because you bypass the setter, and assign the string without retaining it. So when the string gets deallocated on being sent to the autorelease pool, your app crashes.
By synthesizing the accessors using #synthesize and using the dot notation (or setDistanceString:), the object will retain the string for you so that it always has a pointer to it for itself (until it's released).

Objective-C equivalent of Java's BlockingQueue?

I'm just getting into iPhone development after many years doing Java development. I'm looking for the Objective-C equivalent to Java's BlockingQueue. Is there something like that?
In case I'm going about things the wrong way, here's what I'm trying to achieve:
I want to display, one at a time, chunks of data pulled from a network server. To keep the user from noticing network lag, I want to always have a few chunks of data pre-fetched. In Java-land, I'd use a thread-safe queue between my fetching thread and my display thread.
Here's an implementation of a blocking queue with a queue and dequeue method. The expectation would be that one thread goes into a loop calling dequeueUnitOfWorkWaitingUntilDate: and processes units of work while a second thread is calling queueUnitOfWork:.
#interface MyBlockingQueue : NSObject {
NSMutableArray *queue;
NSConditionLock *queueLock;
}
- (id)dequeueUnitOfWorkWaitingUntilDate:(NSDate *)timeoutData;
- (void)queueUnitOfWork:(id)unitOfWork;
#end
enum {
kNoWorkQueued = 0,
kWorkQueued = 1
}
#implementation MyBlockingQueue
- (id)init {
if ((self = [super init])) {
queueLock = [[NSConditionLock alloc] initWithCondition:kNoWorkQueued];
workItems = [[NSMutableArray alloc] init];
}
return self;
}
- (void)dealloc {
[queueLock release];
[workItems release];
[super dealloc];
}
- (id)dequeueUnitOfWorkWaitingUntilDate:(NSDate *)timeoutDate {
id unitOfWork = nil;
if ([queueLock lockWhenCondition:kWorkQueued beforeDate:timeoutDate]) {
unitOfWork = [[[queue objectAtIndex:0] retain] autorelease];
[queue removeObjectAtIndex:0];
[queueLock unlockWithCondition:([workItems count] ? kWorkQueued : kNoWorkQueued)];
}
return unitOfWork;
}
- (void)queueUnitOfWork:(id)unitOfWork {
[queueLock lock];
[queue addObject:unitOfWork];
[queueLock unlockWithCondition:kWorkQueued];
}
#end
You can simply spin off an NSOperation and post a notification when the data has come back (finished loading). Take a look at Dave Dribin's blog post on concurrency with NSOperation that shows how to encapsulate an NSURLConnection session:
http://www.dribin.org/dave/blog/archives/2009/05/05/concurrent_operations/
If you are not talking about accessing a web service or site where NSURLConnection is appropriate, you can instead use Cocoa Async Socket if it's straight TCP/IP or UDP:
http://code.google.com/p/cocoaasyncsocket/
Best Regards,
I don't think such a thing exists natively - you're probably going to have to write your own class that maintains a queue of network objects. Your header might look something like:
#interface ObjcBlockingQueue : NSObject {
// The objects that you're holding onto
NSArray *objects;
}
#property(nonatomic,retain) NSArray *objects;
- (ServerData *)getNextChunk;
Then you can implement getNextChunk to pop and return the top object off your objects array, and if [objects count] is less than a certain value, launch a thread to fetch some more objects (probably using NSURLConnection with ObjcBlockingQueue being the delegate). You can also have that thread/connection launched inside an overridden init method to prefill the queue.
You might also want to think about adding a
- (BOOL)isChunkAvailable;
method that will let your display thread know whether it can display something new right away or if it has to display a loading message. Depending on where you're displaying the data and how your app is structured, it may also be worth your while to make ObjcBlockingQueue a singleton class.