In my program, I am trying to set the property 'frame' of an object stored in an NSMutableArray. When I try to set the frame of the object, my program receives the signal 'SIGABRT' with the message '__[NSCFNumber setFrame:]: unrecognized selector sent to instance 0x6a8d960.' How do I fix this?
for (int i = 0; i < [computerHand count]; i++)
{
CardView* card = [computerHand objectAtIndex:i];
card.frame = CGRectMake(10+70*i, 340, 60, 85);
}
declaration of computerHand:
#property(retain) NSMutableArray* computerHand;
population of computerHand
-(void) addCardToHand:(NSMutableArray *)hand
{
[hand addObject:[cards objectAtIndex:0]];
NSLog(#"%#", [[cards objectAtIndex:0]class]);
[cards removeObjectAtIndex:0];
}
Note- The NSLog prints '__NSCFNumber' to the console.
code for deck population
-(void) createDeck : (UIView *)view
{
cards = [[NSMutableArray alloc]initWithCapacity:52];
for (int i = 0; i <= 4; i++)
{
for(int j = 0; j <= 13; j++)
{
CardView* card = [[CardView alloc] initWithFrame:CGRectMake(view.center.x - 60/2, view.center.y - 85/2, 60, 85) value:j];
[cards addObject:card];
[view addSubview:card];
}
}
for(int i =0; i<= 52; i++)
{
NSLog(#"%#", [cards objectAtIndex:i]);
}
}
Note: the NSLog command correctly prints a CardView object to the console, but then prints __NSCFNumber when trying to access it from a different scope.
Any help is appreciated.
The issue is you're not getting the correct object out of your array. If you break right after you get your CardView out of your array, and print the description in the console, it's a string and not actually a CardView. There are two things you need to do.
Make sure you only add CardViews to your array. Double check this.
In your for loop you can do this to make sure you are only setting frames on CardViews:
if([card isMemberOfClass:[CardView class]]) {
card.frame = CGRectMake(10+70*i, 340, 60, 85);
}
You still want to make sure that you're actually only putting in CardViews though, but this is a way to debug.
Related
I am listing from the mic using AVAudioEngine by this code:
NSError *err2 = nil;
engine = [[AVAudioEngine alloc] init];
mainMixer = [engine mainMixerNode];
[mainMixer installTapOnBus:0 bufferSize:1024 format:[mainMixer outputFormatForBus:0] block:^(AVAudioPCMBuffer * _Nonnull buffer, AVAudioTime * _Nonnull when) {
[self normalize:buffer];
}];
[engine startAndReturnError:&err2];
Then as u see passing the buffer I get into a function called normalize:
-(void) normalize:(AVAudioPCMBuffer*) buffer{
float sum = 0;
NSMutableArray *values = [NSMutableArray new];
for (AVAudioFrameCount i = 0; i < buffer.frameLength; i++) {
[values addObject:#(buffer.floatChannelData[0][i])];
}
for (int i = 0 ; i< [values count]; i++){
if ([values[i] floatValue] != 0){
NSLog(#"%f", [values[i] floatValue]) ;
}
}
}
for now, I only want to print the values of floatChannelData.
The problem is that it is always printing 0. so the buffer has all values 0.
Why is this happening? shouldn't the values be changing with the change of voices received by the mic?
This solved it for me:
Go to your "Info.plist" file.
Right-click and click "Add Row".
Then, in the first column of the newly created row, find the key "Privacy - Microphone Usage Description" and add a suitable explanation of what you intend to do with the audio as the key's value (third column).
Now a dialog box will appear when you run your app asking for permission to access the microphone. Basically, you can't retrieve audio unless you have explicit permission from the user, even if you can technically talk to the audio device and start the audio engine.
i am trying to remove duplicate objects from array.
NSMutableArray* filterResults = [[NSMutableArray alloc] init];
BOOL copy;
// remove duplicate
if (![arrSelectedVehicle count] == 0)
{
for (Vehicles *a1 in arrSelectedVehicle) {
copy = YES;
for (Vehicles *a2 in filterResults) {
if ([a1.Vehicle_id isEqualToString:a2.Vehicle_id]) {
copy = NO;
[arrSelectedVehicle removeObjectIdenticalTo:a2];
break;
}
}
if (copy) {
[filterResults addObject:a1];
}
}
}
i am adding two object which is already their in the array
you cannot modify an array when you are enumerating it. you can do the following:
NSMutableArray* filterResults = [[NSMutableArray alloc] init];
BOOL copy;
// remove duplicate
if (![arrSelectedVehicle count] == 0)
{
NSArray* arraycopy = [arrSelectedVehicle copy];
for (Vehicles *a1 in arraycopy) {
copy = YES;
for (Vehicles *a2 in filterResults) {
if ([a1.Vehicle_id isEqualToString:a2.Vehicle_id]) {
copy = NO;
[arrSelectedVehicle removeObjectIdenticalTo:a2];
break;
}
}
if (copy) {
[filterResults addObject:a1];
}
}
[arraycopy release];
}
You can't modify an array while using it with fast enumeration. That's what the error is telling you. You need to change the loops
for (NSUInteger i = 0; i < arrSelectedVehicle.count; i++) {
Vehicles *a1 = arrSelectedVehicle[i];
copy = YES;
for (NSUInteger j = 0; j < filterResults.count; j++) {
Vehicles *a2 = filterResults[j];
if ([a1.Vehicle_id isEqualToString:a2.Vehicle_id]) {
copy = NO;
[arrSelectedVehicle removeObjectIdenticalTo:a2];
break;
}
}
if (copy) {
[filterResults addObject:a1];
}
}
There are several problems with your code. Anyway, the easiest way to remove duplicates, if you don't care about the order of the elements, is using an NSSet, because an NSSet doesn't allow duplicates:
NSArray *uniqueObjects = [[NSSet setWithArray:arrSelectedVehicle] allObjects];
The error message says it pretty much: you can't modify the contents of a mutable collection while you're using fast enumeration on it (because that's erroneous). You have to make a mutable copy of it, and remove the duplicates from that copy.
you can not use a for loop and then add or remove objects from the array that you are iterating through (arrSelectedVehicle). Instead try building up a new array with the objects that are OK. At the end of the loop you could assign that array back to arrSelectedVehicle.
I am trying to check collisions of objects from a NSMutableArray against another object (using a CGRect) but it keeps saying the method requires a scalar type?!
Here is the method throwing the error:
-(void) checkSquareToCircleCollisions{
NSMutableArray *array = [squares getSquares];
for(int i = 0; i < [squares getCount]; i++){
Square *s = [array objectAtIndex: i];
CGRect rect1 = [player getRect];
CGRect rect2 = [s getRect];
//if(CGRectIntersection(rect1, rect2)){
//[player setAlive: NO];
// }
}
}
Use CGRectIntersectsRect, not CGRectIntersection.
CGRectIntersectsRect returns a boolean: YES if the rectangles intersect. CGRectIntersection returns the CGRect that is the overlap (if any) between the two rectangles.
if (CGRectIntersectsRect(playerRect, squareRect)) {
player.alive = NO;
}
I have to delete an object of an array every now and then, when I do it I get this error.
Collection < CALayerArray: 0xc4f3b20> was mutated while being enumerated
The error appears on this method, which is the accesor of the Array:
- (NSArray *)occupantsArray
{
if (dispatch_get_current_queue() == moduleQueue)
{
return occupantsArray;
}
else
{
__block NSArray *result;
dispatch_sync(moduleQueue, ^{ //ON THIS LINE
result = [occupantsArray copy];
});
return [result autorelease];
}
}
As you can see Im taking care of not returning the original array but a copy, but it still crashes.
Also the method where Im deleting elements of the array is this.
- (void)eraseJIDFromArray:(NSString*)jid{
dispatch_block_t block = ^{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
int i = 0;
for(NSString *jidAct in occupantsArray){
if([jidAct isEqualToString:jid]){
[occupantsArray removeObjectAtIndex:i];
}
i++;
}
[pool drain];
};
if (dispatch_get_current_queue() == moduleQueue)
block();
else
dispatch_async(moduleQueue, block);
}
The array can have upto 200 elements, so it can take some time to go through all of them, but I'm setting queues, dont know what else I can do.
Any ideas?
Thanks.
This code:
for(NSString *jidAct in occupantsArray){
if([jidAct isEqualToString:jid]){
[occupantsArray removeObjectAtIndex:i];
}
i++;
}
is probably causing your problems. You shouldn't be removing elements while enumerating the array. The way you avoid this is by using an NSMutableIndexSet:
NSMutableIndexSet *indexes = [NSMutableIndexSet set]; // assuming NSInteger i;
for(NSString *jidAct in occupantsArray){
if([jidAct isEqualToString:jid]){
[indexes addIndex:i];
}
i++;
}
[occupantsArray removeObjectsAtIndexes:indexes];
I have a UIViewController that has a UIPickerView and UITableView.
The UIPicker has 3 components.
When I try to define the number of components in each array by returning [anArray count], the program freezes without throwing an error when loading the UIViewController.
When I put NSLogs in viewDidLoad: for [self.hours count], [self.minutes count], and [self.meridiem count], the correct number of values are returned.
- (void)viewDidLoad {
[super viewDidLoad];
NSMutableArray *tempHours = [NSMutableArray array];
for (NSInteger i = 0; i < 12; i++) [tempHours addObject:[NSNumber numberWithInteger:(i+1)]];
self.hours = [NSArray array];
hours = tempHours;
[tempHours release];
NSMutableArray *tempMinutes = [NSMutableArray array];
for (NSInteger i = 0; i <= 59; i++) [tempMinutes addObject:[NSNumber numberWithInteger:i]];
self.minutes = [NSArray array];
minutes = tempMinutes;
[tempMinutes release];
NSMutableArray *tempMeridiem = [NSMutableArray array];
for (NSInteger i = 0; i <= 1; i++) [tempMeridiem addObject:[NSNumber numberWithInteger:i]];
self.meridiem = [NSArray array];
meridiem = tempMeridiem;
[tempMeridiem release];
}
Now, in pickerView:numberOfRowsInComponent:Component:, the code freezes without an error if I try to output [anArray count](where anArray is a placeholder for hours, minutes, and meridiem). If I set numberOfRows to an integer value, or to component+1 everything works just fine.
- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component {
NSInteger numberOfRows;
if (component == 0) {
// numberOfRows = component+1;
numberOfRows = [self.hours count];
}
else if(component == 1) {
// numberOfRows = component+1;
numberOfRows = [self.minutes count];
}
else {
// numberOfRows = component+1;
numberOfRows = [self.meridiem count];
}
return numberOfRows;
}
I have a feeling my NSArrays (hours, minutes, meridiem) aren't being retained, but running the Analyzer doesn't show me that I have any memory leaks in that ViewController.
Any and all help would be greatly appreciated!
You are creating unnecessary arrays and not retaining the ones that count. See your code:
self.hours = [NSArray array];
hours = tempHours;
[tempHours release];
Here you created an autoreleased array and set it to your self.hours property (which hopefully has a retain keyword attached to it). But then the very next line you access the ivar directly and set it to tempHours. Then you send a release message to tempHours without having ever retained it. Since tempHours is autoreleased it will magically disappear on the next drain of the auto release pool. I believe what you wanted to do is:
self.hours = tempHours;
Ditto for your other array collections.
These lines are wrong:
self.hours = [NSArray array];
hours = tempHours;
you should just use
self.hours = tempHours;
What was happening in your original code was:
self.hours is set to an array created by [NSArray array]. Call it a. a is correctly retained.
now, hours is set to tempHours. This directly accesses the ivar, without using the setter. So, it doesn't retain tempHours. a is lost without being correctly released, too.
tempHours is released. It's not retained by anybody, so it's dealloc'ed, too.
So, don't do that. You'd like to read the memory management guide. I can't believe the Analyzer (below the Build command) didn't catch this mistake... maybe you'd like to file a bug toward the LLVM team about this case.
The problem was not in the ViewController I was trying to display. I just copied the interface and implementation files into a new proejct, and once I compiled it, everything worked like a dream.
The problem is with the RootViewController of my project that modally invokes the controller with the UIPickerView. Apparently, I have a memory leak in there. Should be trivial to fix.
Thanks everyone for your help!