pathForResource doesn't work - cocoa

I have problem with
NSString *filePaht = [[NSBundle mainBundle] pathForResource:(NSString *)name ofType:(NSString *)ext];
if I used
NSString *filePaht = [[NSBundle mainBundle] pathForResource:#"soundName" ofType:#"aiff"];
it's OK. but when I used
NSString *fileName = [[file.list objectAtIndex:index] objectForKey:#"soundName"];
NSString *filePaht = [[NSBundle mainBundle] pathForResource:fileName ofType:#"aiff"];
It's not work
have any idea !?
Thanks

I am going to guess that fileName from file.list includes the file extension. So you are searching for "soundName.aiff.aiff" which does not exist. Try passing #"" for type or stripping the extension from fileName:
fileName = [fileName stringByDeletingPathExtension];

Check your Debugger Console, as it may be telling what you're doing wrong.
[file.list objectAtIndex:index]
If you're getting an NSRangeException, it may be because index contains an index that is outside the bounds of the array. Remember that arrays in Cocoa are serial, not associative; if you remove an object, the indexes of all the objects that came after it will go down by 1, upholding the invariant that 0 ≤ (every valid index) < (count of objects in the array).
It could also be because you never declared a variable named index.
NSString *fileName = [[file.list objectAtIndex:index] objectForKey:#"soundName"];
NSString *filePaht = [[NSBundle mainBundle] pathForResource:fileName ofType:#"aiff"];
If nothing is happening or you get an NSInternalInconsistencyException, it could be one of:
fileList is nil.
The dictionary returned from [file.list objectAtIndex:index] does not have an object for the key soundName.
If you got a “does not respond to selector” message in the Console, it may be one of:
file.list is an object, but not an NSArray.
[file.list objectAtIndex:index] is not an NSDictionary.
fileName ([[file.list objectAtIndex:index] objectForKey:#"soundName"]) is not an NSString.
Remember that the class name you use when you declare the variable doesn't matter except to the compiler; at run time, it's just a variable holding a pointer to an object. The object can be of any class. It is perfectly valid to put something that isn't an NSString into an NSString * variable; it simply carries a very high (near certain) risk of wrong behavior and/or crashing shortly thereafter.
Such a crash will usually manifest in the form of a “does not respond to selector” exception (after something sends the object a message that NSString objects, for example, should respond to, but that the object doesn't respond to because it isn't an NSString).
Whichever problem you're having, you can use the Debugger to investigate.

Sorry with my fault.
I get data from XML file
and that data include "\n". yes I see "\n" so I replace with #""
but it not enough I must trim space value again.
Thanks for all advice ^_^

Related

NSTreeController - Retrieving selected node

I added Book object in bookController (NSCreeController). Now i want to get stored Book object when i select the row.
- (IBAction)addClicked:(id)sender {
NSTimeInterval timeStamp = [[NSDate date] timeIntervalSince1970];
// NSTimeInterval is defined as double
NSUInteger indexArr[] = {0,0};
Book *obj = [[Book alloc] init];
NSString *dateString = [NSDateFormatter localizedStringFromDate:[NSDate date] dateStyle:NSDateFormatterNoStyle timeStyle:NSDateFormatterLongStyle];
obj.title = [NSString stringWithFormat:#"New %#",dateString];
obj.filename = [NSString stringWithFormat:#"%d",arc4random()%100000];
[self.booksController insertObject:obj atArrangedObjectIndexPath:[NSIndexPath indexPathWithIndexes:indexArr length:2]];
}
I concede there perhaps could be a better solution--
I am unfamiliar with how NSTreeController works, but I looked a the class reference and noticed that it has a content property, similar to an NSArrayController (Which I am familiar with grabbing specific objects from).
I believe that if the content property is actually of type of some kind of tree data structure, my answer here probably won't work. The class reference says this about content:
The value of this property can be an array of objects, or a
single root object. The default value is nil. This property is
observable using key-value observing.
So this is what I historically have done with the expected results:
NSString *predicateString = [NSString stringWithFormat:NEVER_TRANSLATE(#"(filename == %#) AND (title == %#)"), #"FILENAME_ARGUMENT_HERE", #"TITLE_ARGUMENT_HERE"];
NSArray *matchingObjects = [[self content] filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:predicateString]];
Then simply calling -objectAtIndex: will grab you your object. Note that the NSArray will be empty if the object doesn't exist, and if you have duplicate objects, there will be multiple objects in the array.
I also searched for an answer to your question, and found this SO thread:
Given model object, how to find index path in NSTreeController?
It looks pretty promising if my solution doesn't work, the author just steps through the tree and does an isEqual comparison.
If you could (if it's not too much trouble), leave a comment here to let me know what works for you, I'm actually curious :)

Setting UILabel to Same value as NSString

I have searched for hours on this one subject and still have not been able to solve my problem. I have a string value that I need converted into a label. In my code I save the NSString and then make sure I am getting a value with the NSLog (which I DO). Then is where I am having problems. I try to set the label value equal to the nesting but when I run its NSLog I get (null). So my question is how may I make my label equal the value of my string? Thank you so much!
NSString *linkString = self.product[#"link"];
NSLog(#"%#", linkString);
linkLabel.text = linkString;
NSLog(#"%#", linkLabel);
Your NSString will never be equal to your UILabel.
on the other hand, your UILabel's text property which is an NSString will be
try to change the code to this
NSString *linkString = self.product[#"link"];
NSLog(#"%#", linkString);
linkLabel.text = linkString;
NSLog(#"%#", linkLabel.text);
All I changed was linkLabel in your NSLog to linkLabel.text
Assuming like you said that linkString has a value, the second log should output the same as the first log.
EDIT: I saw your comment above, there is no need for a duplicate definition of the label as an #property and above that in the h file.
Are you sure that
NSString *linkString = self.product[#"link"];
works? Try this:
NSString *linkString = #"Test";
and use this for logging:
NSLog(#"%#", linkLabel.text);
Did you forget to hook up the linkLabel in your XIB? Is the value of linkLabel not nil?
What does NSLog(#"%#", linkLabel); print out?

Is alloc+initWithString: same as copy?

Basically, the question is - are the following essentially the same?
NSString *value1 = ...;
NSString *value2 = [[NSString alloc] initWithString:value1];
and
NSString *value1 = ...;
NSString *value2 = [value1 copy];
Conceptually, yes. However, there is one difference: alloc always creates a new string, whereas copy may return the same string.
In particular, immutable objects, such as immutable strings, are likely respond to copy by returning themselves rather than creating and returning a copy. (After all, if you can't change anything about the original, why would you really need a copy?) Mutable strings will respond to it by creating and returning a copy, as you'd expect.
initWithString: is in the middle: It may release the receiver and return the string you gave it, similar to how copy may return the receiver. However, if that happens, it means you wasted the creation of the string you created with alloc. With copy, you may not need to create any additional objects at all.
About the only reason to use alloc and initWithString: is if you have your own subclass of NSString and want to make an instance of it from an existing string. copy won't use your desired subclass. Since subclassing NSString is practically never warranted in Cocoa, the same is true of using initWithString: (or stringWithString:).
So the bottom line is, just use copy (or mutableCopy). It's shorter, clearer about your intent, and can be faster.
Non-mutable strings are treated a bit special, compared to ordinary objects, so in this case, yes, the two operations are the same.
To wit:
NSString *str1 = #"string";
NSString *str2 = [str1 copy];
NSString *str3 = [[NSString alloc] initWithString: str1];
NSLog(#"str1: %p, str2: %p, str3: %p", str1, str2, str3);
Which gives me the following output:
str1: 0x108a960b0, str2: 0x108a960b0, str3: 0x108a960b0
Since the pointer addresses are the same, we are talking about the same object.

componentsJoinedByString gives me EXC_BAD_ACCESS

I have an NSMutableArray i am trying to convert into a string.
Declaring my NSMutableArray...
NSMutableArray *listData;
And later inside a method...
NSString *foo = [listData componentsJoinedByString:#"|"];
NSLog(#"%#",foo);
It seems no matter what i try i keep getting EXC_BAD_ACCESS.
To make sure each element in my array was an NSString i also tried this...
NSMutableArray *mArray = [[NSMutableArray alloc] init];
for (id ln in listData) {
NSString *boo = [NSString stringWithFormat: #"%#",ln];
[mArray addObject:boo];
}
NSString *foo = [mArray componentsJoinedByString:#"|"];
NSLog(#"%#",foo);
I can manipulate my NSMutableArray by adding/deleting objects in the same method or other methods inside my class. But when i try "componentsJoinedByString" the error pops up. Does anyone have any advice or another way i can combine this array into a single NSString?
In the code you've given, there will never be an NSMutableArray for listData. At some point in your code, you'll need to create one, and presumably populate it.
Edit
Okay, so you may get into memory management problems here, so let's be a bit clearer:
You're synthesizing getters and setters for the instance variable, so it's good practice to use those to access it, they'll take care of retain and releasing appropriately.
To set listData you can simply use
self.listData = [listManage getList:[[NSUserDefaults standardUserDefaults] stringForKey:#"list_name"] list:#"LIST"];
or
[self setListData:[listManage getList:[[NSUserDefaults standardUserDefaults] stringForKey:#"list_name"] list:#"LIST"]];
if you prefer.

What is the better way of handling temporary strings?

I have a situation where I need to use some strings temporarily but I've read so many conflicting things that I'm a bit confused as to what the best way to proceed is.
I need to assign some strings inside an if structure but use them outside the if structure so they need to be created outside the if, I was thinking something like:
NSString *arbString = [[NSString alloc] init];
if(whatever)
{
arbString = #"Whatever"
}
else
{
arbString = #"SomethingElse"
}
myLabel.text = arbString;
[arbString release];
I have seen examples where people just used:
NSString *arbString;
to create the string variable
Google's Objective C guide says it's preferred to autorelease at creation time:
"When creating new temporary objects, autorelease them on the same line as you create them rather than a separate release later in the same method":
// AVOID (unless you have a compelling performance reason)
MyController* controller = [[MyController alloc] init];
// ... code here that might return ...
[controller release];
// BETTER
MyController* controller = [[[MyController alloc] init] autorelease];
So I have no idea, which is the best practice?
In the example you posted, you actually lose the reference to the NSString you created when you assign it in arbString = #"Whatever". You then release the string constant (which is unreleasable, by the way).
So there's a memory leak, since you never release the NSString you created.
Remember that all these types are pointers, so = only reassigns them.
As for the question, in this example, you don't need the [[NSString alloc] init]. You don't need to copy the string into a local variable anyway, you can just set myLabel.text to the string constant #"Whatever".
(edit: that's not to say that you can't use your pointer arbString, arbString = #"Whatever"; myLabel.text = arbString is fine. But this is just pointer assignment, not copying)
If you needed to manipulate the string before you returned it, you would create an NSMutableString, and either release or auto-release it. Personally, create autoreleased objects using class methods, so in this example, I'd use [NSString string], or [NSString stringWithString:], which return autoreleased objects.

Resources