views:

2809

answers:

3

in my project i'm using a propertyList for maintaining data. the plist file is named "DataBase.plist". the Root for DataBase.plist is a dictionary which contains 5 dictionaries as child items... now the sub Dictionary contains 4 strings out of which one is always a webaddress with key "URL" (Without the quotes).... i'm running the following code to extract the value for this URL key but it is not working out..

NSString *path = [[NSBundle mainBundle] pathForResource:@"DataBase" ofType:@"plist"];
NSDictionary *rootDict = [[NSDictionary alloc] initWithContentsOfFile:path];
NSString *URLforAll = [[NSString alloc] init];
for (id key in rootDict)
{
 if(key == rowString)
 {
  NSDictionary *dict = [rootDict objectForKey:key];
  URLforAll = [dict objectForKey:@"URL"];
 }
}

the rowstring is a string whose value is the same as the text in the selected cell (i've tested it , it is accurate). PLease help me out if you can.... i'll be thankful

+3  A: 

Hi,

Try using [key isEqualToString: rowString] instead of comparing key and rowString directly using ==. I think == compares the object's pointer values, which will not be equal even if the strings match.

Also - just as an aside, you don't need to initialize URLforAll before setting it. When you set it equal to [dict objectForKey:@"URL"] you lose the pointer to the object you already created and it will be leaked. Instead, just say NSString * URLforAll = nil; or create a new string and autorelease it so that the object will be automatically cleaned up:

NSString * URLforAll = [[[NSString alloc] init] autorelease];

Ben Gotow
All good suggestions. You're correct that == compares memory addresses (pointers). Unlike C++, Objective-C does not support overloaded operators. In fact, this same mistake plagues even Java developers, too. I might avoid creating an autoreleased object first — if URLforAll (poorly named) is nil after the for loop, create an object then. It should probably only be autoreleased if it's being returned from a method.
Quinn Taylor
FIrst - thanks a ton for helping out -isequalToString worked perfectly.... .. . .... and After the above code I do add [URLforAll release]; instead of using [[[NSSTring alloc] init] autorelease]; does memory still gets leaked... if it does please tell me how... please do tell me... and also i read somewhere that using autorelease for iphone is not suggested.... and about the name URLofAll it was changed for the question... thanks a million for the help
valiantb
You don't need to alloc/init URLforALl at all. Just initialize it to nil. The dictionary's objectForKey: method will return you give you an autoreleased object.
amrox
That's true if you can guarantee that the if condition inside the for loop will be true for one of the keys. Without that guarantee, the variable may be nil, which might be problematic. The code snippet isn't enough to tell, and the code isn't very self-evident, either. We're all just guessing what the intent is...
Quinn Taylor
+2  A: 

You also don't need to loop through the dictionary. Just ask it for the data you want.

NSString *path = [[NSBundle mainBundle] pathForResource:@"DataBase" ofType:@"plist"];
NSDictionary *rootDict = [[[NSDictionary alloc] initWithContentsOfFile:path] autorelease];
NNSString *URLString = [[rootDict objectForKey:key] objectForKey:@"URL"];

// do something or return  URLString...
amrox
An excellent point! If keyString isn't found in rootDict, it will return nil and the outer objectForKey: will have no effect. Man, I love Objective-C's handling of messages to nil... :-)
Quinn Taylor
actually looping through the dictionary is necessary for the project knowing that the keystring always contains a value.... Thanks a lot for help...... Thanks a million
valiantb
+1  A: 

Further, in your code:

NSString *URLforAll = [[NSString alloc] init];

This never makes senses. Here are some issues:

  • You are allocating an object, which you then overwrite indiscrimanently with "URLforAll = [dict objectForKey:@"URL"];". So you would need to release it before overwriting it.
  • It is allocated (ie, at the end of the loop, you "own" it and will have to release it. But [dict objectForKey:@"URL"] returns an object which you don't own. So at the end of the loop, you don't know whether you own URLforAll or not.
  • And finally, [[NSString alloc] init] never makes sense because you should just use @"", which returns a constant, empty, NSString which is impervious to retain/release/autorelease issues.

Dealing also with the isEqualToString issue, but ignoring amrox's much better solution, the code would be:

NSString *path = [[NSBundle mainBundle] pathForResource:@"DataBase" ofType:@"plist"];
NSDictionary *rootDict = [[NSDictionary alloc] initWithContentsOfFile:path];
NSString *URLforAll = @"";
for (id key in rootDict) {
        if ( [key isEqualToString:rowString] ) {
                NSDictionary *dict = [rootDict objectForKey:key];
                URLforAll = [dict objectForKey:@"URL"];
        }
}
[[URLforAll retain] autorelease];
[rootDict release];

Note that objectForKey may well return an internal reference to the object which will become invalid when you release the dictionary, hence the need for retaining the object if you want to keep it around longer than the life of the dictionary.

amrox's use of:

NSString *path = [[NSBundle mainBundle] pathForResource:@"DataBase" ofType:@"plist"];
NSDictionary *rootDict = [[NSDictionary alloc] initWithContentsOfFile:path];
NSString *URLString = [[rootDict objectForKey:key] objectForKey:@"URL"];
[[URLString retain] autorelease];
[rootDict release];
if ( !URLString ) {
    URLString = @"";
}

is a better solution, but you should undertand what is wrong with your original solution as well.

Peter N Lewis
THANKS A MILLION>>>> I OWE YOU
valiantb