arrays are not adding to the nsmutabledictionary - objective-c

i am adding the arrays to an nsmutabledictionary but its giving 0 count
i allocated the dictionary in viewDidLoad method.
can any body help me out please..
thanks.
- (void)creatingDictionary{
songsDict = nil;
NSMutableArray *hrSongs = [[NSMutableArray alloc]init];
for(int i=0;i<[onAirSongs count];i++){
for(int j=i;j<[onAirSongs count];j++){
Song *a1 =(Song *)[onAirSongs objectAtIndex:i];
Song *a2 =(Song *)[onAirSongs objectAtIndex:j];
if(a1.cellId == a2.cellId)
[hrSongs addObject:a2];
else{
[songsDict setObject:hrSongs forKey:[NSString stringWithFormat:#"%d",i]];
hrSongs = nil;
i=j-1;
break;
}
}//inner for
}//out for
[hrSongs release];
NSLog(#"songsdictionary count....%d",[songsDict count]);
}

You're setting songsDict to nil. You can't add an array to a dictionary that doesn't exist.

blindJesse is correct, but there are more problems here:
You are setting songsDict to nil. In Objective-C, nil-eats-messages and, thus, you are silently not doing anything at all when you [songsDict setObject:.....].
In the middle of the loop, you hrSongs = nil;. Subsequent iterations through the loop will happily call addObject: on nil, doing nothing at all.
This whole thing seems kinda weird; what does onAirSongs contain? Cells? This seems like you haven't really preserved any kind of Model-View-Controller separation. It might work, but you are in for a severe maintenance headache down the road if you ever have to change your UI.

Related

[NSArray arrayWithObjects: nil, nil]

I have a property self.shareURL that may or may not be nil and I'd like to wrap it in array. Obviously, if it's nil I can't do that, so I'd like to have an empty array in that case. So I can write:
NSArray *items = [self shareURL] ? #[[self shareURL]] : #[];
However, I can construct it in one call to shareURL, like this:
NSArray *items = [NSArray arrayWithObjects:[self shareURL], nil];
This works because arrayWithObjects: will stop anyway once it sees the first nil and the stack is not corrupted because Objective-C ABI doesn't require it to clear the varargs in the stack.
Is it ok to use the second form? Or is the first one more clear?
Both options seem ok, but if you are asking for which one is more clear, I'd go for this one:
NSArray *items = [self shareURL] ? #[[self shareURL]] : #[];
Why? Because you are implementing the behaviour you want to achieve in that line, not as a consequence of something happening on the stack like on the second approach. In other words, you are achieving the behaviour you are specifying in the line.
If I'm a developer and I see that code, with the 1st approach I'll understand the behaviour, without any explanation.
Rather than terseness, I would opt for readability:
NSArray *items = nil;
if ([self shareURL]) {
items = #[[self shareURL]];
} else {
items = #[];
}
Both ways are OK, and the first one you can write like this:
NSArray *items = [self shareURL] ? : #[];
This is right.
NSArray *items = [self shareURL] ? #[[self shareURL]] : #[];
Ok, for the record, I actually went with
NSMutableArray *items = [NSMutableArray new];
if (self.shareURL) {
[items addObject: self.shareURL];
}
as it makes more clear that there is a "default" state of empty array, and we try to add one object.

componentsJoinedByString causing crash with EXC_BAD_ACCESS

I'm pretty sure this is eactly the same problem as in componentsJoinedByString gives me EXC_BAD_ACCESS
basically, an array is populated using this code, with ARC turned on:
-(NSMutableArray *)getArrayOfCommaSeparatedSelectorStrings{
NSMutableArray *Array = [[NSMutableArray alloc] init];
for(NSMutableArray *e in [self getArrayOfSelectorArrays]) {
[Array addObject:[displayCSSInformation returnArrayAsCommaList:e]];
}
return Array;
}
and then displayCSSInformation tries to return a comma separated list with this method :
+(NSString *)returnArrayAsCommaList:(NSMutableArray *)ToBeConverted{
NSString *test = [ToBeConverted componentsJoinedByString:#", "];
return test;
}
Thanks for your help.
There's usually no need to use a separate method if all that method does is invoke another method. Remove your +returnArrayAsCommaList: method and just use componentsJoinedByString: on the array directly.
- (NSMutableArray *) getArrayOfCommaSeparatedSelectorStrings
{
NSMutableArray *array = [[NSMutableArray alloc] init];
for (NSMutableArray *e in [self getArrayOfSelectorArrays])
[array addObject:[e componentsJoinedByString:#", "]];
return array;
}
The above should work (it works in my small test example), if you are still getting errors:
Make sure that getArrayOfSelectorArrays is actually returning an array of array of strings. Log the output to the console or step through with a debugger.
Use the “Build & Analyze” option to have the static analyser check for any issues. This is less of an issue with ARC but it will still pick up things such as using uninitialised values.
Make sure you have properly bridged ownership from any Core Foundation objects.

Objective C: Why doesn't my NSMutableArray work?

I'm quite new to ObjC and its mutable arrays. This is driving me crazy ;-)
I do the following:
mColumns = [NSMutableArray array];
for( int i=0; i<5; i++ ) [mColumns addObject:[[MyColumn alloc] init]];
After that code my array "mColumns" contains 5 elements. But each of them is a NULL-Pointer! (Or at least that's what the debugger tells me).
I already checked that the code
[[MyColumn alloc] init]
Gives me some valid objects, so I have no idea why my array gets filled with 0x0s.
Can you give me a hint?
Retain your mutableArray if you want it to stick around. At the end of the current event-loop it will be automatically deallocated, as it is in the autoreleasePool.
At that point all bets are off. Your mColumns variable just points to a junk piece of memory, maybe another object, maybe half an object, maybe even you can still get the correct count or even a contained object, but at some point your app will crash.
Just a quick point, if [[mColumns objectAtIndex:x] addObject:g]; crashes your app is it [mColumns objectAtIndex:x] that is causing the crash or is it addObject:g ?
Why not put them on separate lines and find out?
I know you say that the objects are allocated correctly but I'd be inclined to check it. Here's the same code with more debugging:
NSMutableArray *mColumns = [NSMutableArray array];
for( int i=0; i<5; i++ ) {
MyColumn *col = [[MyColumn alloc] init];
NSLog(#"%d: %#", i, col);
[mColumns addObject:col];
[col release];
}
NSLog(#"Array has %d elements, first is %#", [mColumns count], [mColumns objectAtIndex:0]);
The problem is likely to be either (a) the object is not being created correctly, or (b) the array does have the elements and you have a different problem.
Hmmm. I can see one problem in your code, but not one that would cause this issue: you are adding retained objects to the array; you'll want to autorelease those first so you don't leak.
As for your actual problem, I don't know. It's impossible to fill an array with null pointers; only objects of type id (not arbitrary pointers) can be put inside of an NSArray/NSMutableArray.
I know you said that you have checked -[MyColumn init], but it would be a good idea to check that it is producing the proper objects in this very spot.
columns = [NSMutableArray array];
for (int i = 0; i < 5; i++) {
id c = [[[MyColumn alloc] init] autorelease];
/* set a breakpoint here, and type `po c`
into the debugger to see what was created
*/
[columns addObject:c];
}
Unless -[MyColumn init] is making some really funky objects, I can't figure out what the problem would be. I wonder whether something weird is happening to mColumns; is it retained by anything, for instance?

why the tableview doesn't show binding data?

Here's my code of generating data
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
// Insert code here to initialize your application
[array initWithCapacity:20];
}
- (IBAction) readlog:(id)sender {
for (int i = 0; i < 20; i++) {
NSDictionary *d = [NSDictionary dictionaryWithContentsOfFile:[path stringByAppendingFormat:#"/%d.log",i]];
[array addObject:d];
}
}
- (IBAction) writelog:(id)sender {
for (int i = 0; i < 20; i++) {
NSMutableDictionary *d = [NSMutableDictionary dictionary];
NSString *name = [NSString stringWithFormat:#"testfile%d", i];
[d setObject:[NSDate date] forKey:#"date"];
[d setObject:[path stringByAppendingFormat:#"/%d.log", i] forKey:#"path"];
[d setObject:name forKey:#"name"];
[d writeToFile:[path stringByAppendingFormat:#"/%d.log", i] atomically:YES];
}
and I bind my tableview column with appdelegate.array with keypath name/path/date
but it doesn't show any data in the array.. is there anything wrong here?
Thanks!
You haven't created an array.
init methods, including NSMutableArray's initWithCapacity:, initialize an existing (freshly-created) instance. You haven't created one, so you're sending that initWithCapacity: message to nil, which means it has no effect.
You need to create the array, then initialize it, then assign it to your array variable, preferably all in the same line.
There's also the issue that your table view will have already asked for the array by the time you receive the applicationDidFinishLaunching: message. You don't have one yet, so it gets nothing; by the time you create one, it has already asked you for it and gotten its answer, and does not know that it should ask again.
Create your array in init or initWithCoder: (I believe you will need the latter if your app delegate is in a nib), and implement and use Key-Value-Coding-compatible accessor methods to fill the array with values. When you send yourself accessor messages, you'll cause KVO notifications that will tip off the table view that it needs to ask for the array again. Assigning directly to the instance variable will not cause this effect.
A couple of other things…
You have three [path stringByAppendingFormat:#"/%d.log", i] expressions in two different methods. Don't repeat yourself. Move that to a method named something like logFileNameWithLogFileNumber: and send yourself that message to generate the filename. This will make the code both clearer and easier to maintain.
Finally, as a matter of style, you should not use stringByAppendingFormat: or stringWithFormat: to construct paths. Use stringByAppendingPathComponent: (in this case, together with stringWithFormat: to generate the filename). Clarity and pathname-separator-independence are virtues.

Reusing NSMutableArray

I'm getting some leaks (obvserved by Instruments) when trying to reuse an existing NSMutableArray (in order to save memory).
Basically I'm creating an NSMutableArray, filling it with objects (UIImages) and passing it onto another object which retains it. However, I now need to use an NSMutableArray again. I figured I would release all its objects, empty it, and everything would be fine, but Instruments reports a CALayer leaked object (??) from that very method which looks something as follows:
NSString *fileName;
NSMutableArray *arrayOfImages = [[NSMutableArray alloc] init];
// fill the array with images
for(int i = 0; i <= 7; i++) {
fileName = [NSString stringWithFormat:#"myImage_%d.png", i];
[arrayOfImages addObject:[UIImage imageNamed:fileName]];
}
// create a button with the array
aButton = [[CustomButtonClass buttonWithType:UIButtonTypeCustom]
initWithFrame:someFrame
imageArray:arrayOfImages];
// release its objects
for(int i = 0; i < [arrayOfImages count]; i++) {
[[arrayOfImages objectAtIndex:i] release];
}
// empty array
[arrayOfImages removeAllObjects];
// fill it with other images
for(int i = 0; i <= 7; i++) {
fileName = [NSString stringWithFormat:#"myOtherImage_%d.png", i];
[arrayOfImages addObject:[UIImage imageNamed:fileName]];
}
// create another button with other images (same array)
aSecondButton = [[CustomButtonClass buttonWithType:UIButtonTypeCustom]
initWithFrame:someFrame
imageArray:arrayOfImages];
[arrayOfImages release];
For the sake of clarity, my button init method looks as follows:
- (id)initWithFrame:(CGRect)frame
images:(NSArray *)imageArray
{
if(self = [super initWithFrame:frame]) {
myImageArray = [[NSArray arrayWithArray:imageArray] retain];
}
return self;
}
I know I could just create a new NSMutableArray and be over with this issue but it annoys me not to be able to just reuse the old array. What could be the problem?
I'm getting some leaks (obvserved by
Instruments) when trying to reuse an
existing NSMutableArray (in order to
save memory).
An array takes a really small amount of memory; 4 bytes per pointer stored (on a 32 bit system) + a tiny bit of overhead. Reusing an array to attempt to save memory is a waste of time in all but the most extraordinary circumstances.
// release its objects
for(int i = 0; i < [arrayOfImages count]; i++) {
[[arrayOfImages objectAtIndex:i] release];
}
// empty array
[arrayOfImages removeAllObjects];
You didn't retain the objects and, thus, you shouldn't be releasing them! That your app didn't crash after the above indicates that you are likely over-retaining the objects somewhere else.
I know I could just create a new
NSMutableArray and be over with this
issue but it annoys me not to be able
to just reuse the old array. What
could be the problem?
There isn't anything in that code that springs out as a memory leak. Just the opposite; you are over-releasing objects.
And the above indicates that you really need to revisit the memory management guidelines as re-using an array versus releasing the array and creating a new one really doesn't have anything to do with this problem.
You don't need this part:
// release its objects
for(int i = 0; i < [arrayOfImages count]; i++) {
[[arrayOfImages objectAtIndex:i] release];
}
This is against the ownership rule. You didn't retain the images at
[arrayOfImages addObject:[UIImage imageNamed:fileName]];
so it's not your responsibility to release them. It's NSMutableArray that retains them when -addObject is called, and so it's NSMutableArray's responsibility to release them when -removeObject or others of that ilk is called. The leak you found might be because the system got confused by this over-releasing...
I would also recommend to perform "Build and Analyze" in XCode.
The Leaks instrument tells you where the object that leaked was first allocated. The fact one of the images was leaked means that you used the image somewhere else, and did not release it there - Leaks cannot tell you where since it cannot show you code that does not exist.
Indeed as others have pointed out this is somewhat surprising since the code as-is is over-releasing objects and should have crashed. But the fact it did not crash is a good sign somewhere else you are using the images from the array and over-retaining them.