NSMutableArray removeObject: throwing an error [duplicate] - objective-c

This question already has answers here:
Unrecognized selector when adding an object to NSMutableArray
(2 answers)
Closed 8 years ago.
I have an #property (nonatomic,copy) NSMutableArray* children;, and I'm adding/removing items to this array.
Here's the surprise:
- (void)addChildDocument:(PPDocument *)doc {
[_children addObject:doc];
}
- (void)removeChildDocument:(PPDocument*)doc {
[_children removeObject:doc];
}
The first one works fine. The second one doesn't.
-[__NSArrayI removeObject:]: unrecognized selector sent to instance
Can you please explain to me exactly what is going on and how the children array suddenly shows up as immutable?
UPDATE:
The issue has been resolved. However, as weird as it may strike you, the copy most of you referred to had nothing to do with the issue. Weirdly it had to do with a parent property of each PPDocument not being correctly set as weak. Once I did that (and leaving the children as it was), everything works fine - as expected. And NSMutableArrays remain mutable whatsoever.

You must be doing:
obj.children = #[ #"Some", #"immutable", #"array" ];
between those calls.

You can't remove what you're adding in the method. You need to give him an array index.
For example,
[_children removeObject:[_children lastObject]];
if you know that it's always gonna be the last one.
If its not, please provide a comment with more explanation on where the object can be.
Edit : actually you might be able to do the following, could you try too?
[_children removeObjectAtIndex:[_children indexOfObject:doc]];

Related

ARC deallocate my NSmutablearray before NSTableview reloaddata

My NSMutableArray lOfSegments, declared as IVAR, get populated correctly. During the debug it shows 4 object in the array.
for (int x=0; [arrayOfSegmentsTcIn count]>x; x++) {
NSDictionary *segmentDic=[[NSDictionary alloc] initWithObjectsAndKeys: [arrayOfSegmentsNumbers objectAtIndex:x],#"segment",[arrayOfSegmentsTcIn objectAtIndex:x],#"tc_in",[arrayOfSegmentsTcOut objectAtIndex:x],#"tc_out", nil];
[lOfSegments addObject:segmentDic];
[myDMXML.segments addObject:segmentDic];
}
[self.xmlTCLable setStringValue:[myDMXML startTimeCode]];
[self.xmlDurationLable setStringValue:[myDMXML duration]];
[self xmlValidationCheck];
NSLog(#"arrayController:%#",[lOfSegments valueForKey:#"segment"]);
[self.tableViewOutlet reloadData];
NSLog list the array correctly but when reloadData is executed the code jumps to
- (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView {
return [lOfSegments count];
}
The array is null.
The Object is initialised in viewDidLoad as
lOfSegments = [[NSMutableArray alloc]init];
Please Help!
First, I recommend making your code more clear here by using self.lOfSegments rather than directly accessing an ivar. (The fact that the ivar lacks a leading _ is very suspicious as well, and raises the question of whether this is even the variable you think it is.)
On the assumption that this is the variable you think it is, and that you have overridden the standard behavior to make the ivar match the property or created explicit ivars (neither of which you should do), there are several common causes for this kind of problem:
The most likely cause is that you called your initialization code prior to viewDidLoad and then viewDidLoad blew away the array. Many things can run prior to viewDidLoad, and viewDidLoad can run more than once (at least this used to be true; I'd have to study whether the view-loading changes in iOS 6 made it guaranteed to be run once.)
You have some other way reset lOfSegments between the time your initialization code ran and the time reloadData ran. If you would reliably use self. then you could override setLOfSegments: so you could log this. Or you could mark this property readonly so you could prevent it. Thats one of many reasons that you should use properties, not ivars.
The setting code failed to run before reloadData. Ensure that the log statement actually printed prior to getting to reloadData and is on the same queue (the queue identifier will be part of the NSLog output in brackets). I don't think this is likely given your description, but it is a common problem.
There are two instances of this object. Make sure that the object that ran your initialization code is the same object that ran reloadData. This is a more common mistake then you may think. Log self and make sure the memory address is the same in both cases.
looks like you have variable with same name lOfSegments in method viewDidLoad. So in viewDidLoad you use stack variable, in numberOfRowsInTableView - instance variable.
Or maybe tableViewOutlete.dataSource pointing on different viewController

Crash happening when using removeObjectsInArray:[NSArray arrayWithArray:] [duplicate]

This question already has answers here:
crash while removing objects from NSMutableArray
(6 answers)
Closed 8 years ago.
self.filteredProducts = [[NSMutableArray alloc] init];
//Find products
self.filteredProducts = (NSMutableArray*)[(NSMutableDictionary *)[self.CECategoriesDictionary objectForKey:category.categoryGuid] allValues];
if([self.oldfilteredProducts count] > 0 && selectedLevel==5)
{
NSMutableArray *diff = [self.filteredProducts mutableCopy];
[diff removeObjectsInArray:[NSArray arrayWithArray:self.oldfilteredProducts]];
[self.filteredProducts removeObjectsInArray:[NSArray arrayWithArray:diff]];
}
Logs :
[__NSArrayI removeObjectsInArray:]: unrecognized selector sent to instance 0x1aed19d0
2014-09-15 22:00:19.243 SAPRetailEx[10325:90b] [ERROR]:Uncaught exception: -[__NSArrayI removeObjectsInArray:]: unrecognized selector sent to instance 0x1aed19d0
2014-09-15 22:00:19.243 SAPRetailEx[10325:90b] [ERROR]:-[__NSArrayI removeObjectsInArray:]: unrecognized selector sent to instance 0x1aed19d0
2014-09-15 22:00:19.248 SAPRetailEx[10325:90b] [ERROR]:(
you cannot remove objects form NSArray; I know you think you are using an NSMutableArray but you are not. This is made quite clear from your error [__NSArrayI removeObjectsInArray:]: unrecognized selector; __NSArrayI is an immutable object (that is what the I means), if this were really a mutable array the class would be __NSArrayM.
you seem to be operating under the false impression that you can get a mutable array simply by casting an NSArray to NSMutableArray; this has never been how casting works under any C derived language. You instead need to send a mutableCopy message to the NSArray. Of course you now have a copy of the array so modifications arent reflected in the original. you also own the copy so if you arent using ARC you need to release the copy when you are done.
I'm curious to know why you are already making a mutableCopy of self.filteredProducts then also trying to remove directly from self.filteredProducts. even if this worked how you expect you are now copying the array for no reason then removing from both thee "original" and the "copy".
self.filteredProducts isn't really an NSMutableArray It's just a normal NSArray which doesn't have a "remove option".
[self.filteredProducts removeObjectsInArray:[NSArray arrayWithArray:diff]
To help in the future... set at break point in your code after you assign it, then print out the description and see what type of object it really is. either po in the debugger or right click on "Print Description". Don't believe what is says on the left panel, that's just what you told the code the object is, look at the description on the right to see what it really is.

Changing value of a NSString

I am having problems changing the value of an NSString.
It is declared in my class like this:
#property (strong, nonatomic)NSMutableString *votes;
When the object is created, it is set like this:
song.votes = [dict objectForKey:#"Votes"];
And finally is where the trouble occurs. Later in my code I try to modify the value like this:
song.votes =[responseArr valueForKey:#"CNT"];
This line is leading to this crash:
'NSInvalidArgumentException', reason: '-[__NSCFString setVotes]:
unrecognized selector sent to instance 0x14f84430'
I'm think my problems is caused by one of these:
1. Incorrectly setting the properties above. I've tried setting it as (copy, nonatomic) as well but it does the same thing.
2. i need to use an NSMutableString for this. I tried changing it to NSMutableString but it still crashes when it changes (admittedly I am initializing and changing it the way way when using NSMutableString, am not entirely sure how to change things when its Mutable.
I think the problem is in the way you're allocating / setting your song object. Somewhere between setting the first and the second value, you're probably deallocating song and then trying to set it's properties, or you're modifying it in such a way that it's not the same class type anymore.
unrecognized selector sent to instance 0x14f84430' pretty much sums it up for you. The second time you try to set the votes property, it tries to access the synthesized setter (setVotes) from song which is no longer the class you think it is.
From the error it looks like you may be re-allocating song as a NSString object. That's why it's trying to access a setVotes method on NSString and such a method does not exist, so it bails out and crashes.
Are you sure you're not doing something like song = [someString retain]; ?
Use -mutableCopy if you need a mutable copy of your NSString.
song.votes = [[dict objectForKey:#"Votes"] mutableCopy];
Assuming responseArr is an array, [responseArr valueForKey:#"CNT"] returns an array with the return value of each of the instances in responseArr. Your property is for a NSMutableString, but you set it to a NSArray.
(Also, do provide the actual error that you get when you crash instead of just saying 'it crashes'.)

AXUIElementRef and ARC - Deallocated instances and __bridge vs __bridge_transfer

I get this error on an NSMutableArray:
-[Not A Type release]: message sent to deallocated instance 0x1006e29c0
It happens on this line:
[_array removeAllObjects];
Now, I understand what the error means but not why it happens in this case.
I've added an NSLog right before the above line like so:
NSLog(#"%#", [_array class]);
And this executes normally and with the correct behavior, this is the log:
2013-03-13 11:19:27.366 App[66921:303] __NSArrayM
2013-03-13 11:19:27.367 App[66921:303] *** -[Not A Type release]: message sent to deallocated instance 0x1006e29c0
So right before removing it doesn't seem to be deallocated..
Even if I remove the removeAllObjects call and replace it with the below line, I still get the same error.
_array = [[NSMutableArray alloc] init];
All I'm doing elsewhere in the code is calling [_array addObject:...]
_array is a strong property:
#property (strong) NSMutableArray *array;
The array is first initialized in the init method.
EDIT: I'm adding AXUIElementRefs to this array like so:
[_array addObject:(__bridge_transfer id)elementRef];
I thought the __bridge_transfer brings it over to ARC and I wouldn't need to manage any of that?
What could be the problem?
UPDATE:
Here is a sample project: http://users.telenet.be/prullen/AXMemory.zip
This is a working project as I'm using __bridge and not __bridge_transfer.
This project contains a simple loop that does the same thing over and over again. This is to demonstrate that with just __bridge, the AXUIElementRefs never get released. They stay in memory. That's what I see in the Instruments profiler too. You can also see the memory usage increasing every few seconds via activity monitor.
The AXUIElementRefs were obtained via AXUIElementCopyMultipleAttributeValues - so I would assume that I would have ownership of them? Nevertheless, changing to __bridge_transfer results in the errors above.
If anyone could take a look at this and let me know what I'm doing wrong, that would be much appreciated.
I get an array of properties via the following statement: (line 60).
AXUIElementCopyMultipleAttributeValues(frontWindowRef, attributes,0,&attributeValues);
Line 110 I assign the AXUIElement (looping over the children array):
element = CFArrayGetValueAtIndex(childrenArrayRef, i);
Line 112 is where I add the AXUIElementRef to the array:
[_array addObject:(__bridge id)(element)];
Line 36 is where I empty it if it's over 500 elements:
if ([_array count] > 500) {
[_array removeAllObjects];
}
You can't just assume that __bridge_transfer "brings it over to ARC and [you] wouldn't need to manage any of that". You have to understand what rights and responsibilities you had for elementRef at the time (which we can't tell from what you've written).
I find it's much easier to understand the bridge casts if you use the corresponding CFBridgingRetain() and CFBridgingRelease() functions. __bridge_transfer is the same as CFBridgingRelease(). So, the question is: do you own elementRef at the time? Is it appropriate for you to release it?
Consider, would the following have been correct?
[_array addObject:(__bridge id)elementRef];
CFRelease(elementRef);
If not, then neither is __bridge_transfer.
From the nature of the error you're getting, I strongly suspect you were not entitled to release elementRef, so you were not entitled to tell ARC that it owns it and must release it. You have caused the AXUIElementRef to be over-released. You should just have used a __bridge cast – no "transfer" and no CF…Release().

Problem assigning value obtained from [array objectAtIndex:]

In my Piano class, I have a property (Keys is another custom class)
#property (nonatomic, retain) Keys *lastPlayed;
In one of my Piano methods, I set the value of lastPlayed using an object from an array of Key objects.
self.lastPlayed = [allKeys objectAtIndex:variable];
The above line of code causes the program to crash.
I've noticed that if I hardcode a specific Key object from the allKeys array, then it works fine. Like so:
self.lastPlayed = keyC;
Interestingly, it doesn't crash if I put the crashing code into a different method.
How can I prevent the crash?
EDIT:
I call this method in the Keys class, where my piano is the delegate
[delegate deliverTagwithNameTag:self.tag]
the piano then responds
- (void) deliverTagwithNameTag:(int)nameTag {
self.lastPlayed = [allKeys objectAtIndex:nameTag];
}
You're probably not getting a plain unexplained crash, you're probably raising an exception. You can watch the console to find out which exception you raised. Normally in this sort of situation it'll be something useful to tell you either that you're asking the array for an out-of-bounds value (which could happen if variable were collecting an incorrect value somehow), that the array itself is invalid (which could be a memory allocation problem) or that the thing returned can't be stored as lastPlayed (which would normally indicate you're doing something custom in the setter and getting an unexpected type of class).
So to prevent the crash, check your console and look for one of those problems.