How do I removeAllObjects on my NSMutableArray that is part of another object? - iphone

I have an object defined like this:
Scores.h:
#interface Scores : NSObject {
NSString *sentenceKey;
NSMutableArray *scorrectAnswers;
}
#property (nonatomic, copy) NSString *sentenceKey;
#property (nonatomic, copy) NSMutableArray *scorrectAnswers;
+ (id)addScore:(NSString *)senKey;
- (id)initWithSentenceKey:(NSString *)sKey
scorrectAnswers:(NSMutableArray *)scorrectAs;
- (id)initWithSentenceKey:(NSString *)sKey;
- (void)removeArrayObjects;
Score.m:
#import "Scores.h"
#implementation Scores
#synthesize sentenceKey, scorrectAnswers;
+ (id)addScore:(NSString *)senKey
{
Scores *newScore = [[self alloc] initWithSentenceKey:senKey
scorrectAnswers:[NSMutableArray new]];
return [newScore autorelease];}
I'm trying to removeAllObjects on my mutable array with this method:
- (void)removeArrayObjects;{
[scorrectAnswers removeAllObjects];}
...which I call from another program like this:
for (Scores *sScore in scores)
{
[sScore removeArrayObjects];
}
... and I get this error when I run it:
-[__NSArrayI removeAllObjects]: unrecognized selector sent to instance 0x53412d0
Can anyone tell me what I'm doing wrong here? Thanks.

You are not dealing with an NSMutableArray as the error indicates you have an immutable NSArray.
This question may be your answer NSMutableArray addObject: -[__NSArrayI addObject:]: unrecognized selector sent to instance
Basically the copy you used when defining your #property will cause the setter to be generated using
scorrectAnswers = [newMutableArray copy];
which returns an immutable NSArray.
You can re-implement this method and change the previous line for:
scorrectAnswers = [newMutableArray mutableCopy];
or use retain instead of copy
This can also occur when getting data from a plist
If you are using a plist it will return an NSArray even if you save an NSMutableArray it will be cast. So when retrieving you will need to do something like:
scorrectAnswers = [[NSMutableArray alloc] initWithArray:[userDefault objectForKey:#"my_array_key"]]

It doesn't look like like the memory pointed to by scorrectAnswers is actually pointing to an NSMutableArray. Where and how do you initialize that variable? If you are setting the ivar directly with an autoreleased object, like:
scorrectAnswers = [NSMutableArray arrayWithCapacity:10];
then the autoreleased array will be destroyed, since you're not retaining it (or copying it). If that memory gets reallocated to point to another object, you'll see an error like the one you're getting, with an unexpected type. If the memory has not been reallocated, you'll get an EXC_BAD_ACCESS error.

Similar to what was mentioned above, I had an NSMutableArray which was being re-allocated somewhere in my code as an NSArray. Once I modified that to correctly be an NSMutableArray, it resolved my problem.
I would suggest doing a quick search to ensure that you have not reallocated the array somewhere in your project and modify accordingly.

Related

Error in accessing global declared NSArray values in class methods

I have problem in fetching the element from array,
I have declared NSArray *array globally, also tried through myfile.h file property, but I'm not able to access array element in my view controller setCode method.
NSArray *array;
//this is global array also i tried in my.h file
//#property(nonatomic, retain) NSArra *array;
//and by accessing it #synthesize array; also not works for me.
-(void)viewDidLoad
{
array = [NSArray arrayWithObjects:#"sssss", #"hjjjjj", #"kkkkkk"];
[self setCode];
}
-(void)setCode
{
NSString *code = [array objectAtIndex:0];
NSLog(#"code %#",code);
}
#end
It throwing some errors:
2013-08-05 16:25:28.429 test_project_ios_31st_july[2409:c07] -[__NSMallocBlock__ objectAtIndex:]: unrecognized selector sent to instance 0x9c82350
2013-08-05 16:25:28.430 test_project_ios_31st_july[2409:c07] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSMallocBlock__ objectAtIndex:]: unrecognized selector sent to instance 0x9c82350'
*** First throw call stack:
(0x23fb012 0x1c98e7e 0x24864bd 0x23eabbc 0x23ea94e 0x283f 0x17594f9 0x24550c5 0x23afefa 0x168dbb2 0x16a0e6b 0xdb9f 0x16d2417 0x16ebb24 0x16a0d60 0x174da8a 0x43ac2 0x16d2417 0x16ebb24 0x16a0d60 0x174da8a 0x464d5 0x17594f9 0x24550c5 0x23afefa 0x16a0a0c 0xa3d0e6 0x206353f 0x2075014 0x20657d5 0x23a1af5 0x23a0f44 0x23a0e1b 0x2ad87e3 0x2ad8668 0xbdcffc 0x2192 0x20c5)
libc++abi.dylib: terminate called throwing an exception
Please try following code:
NSArray *array;
-(void)viewDidLoad
{
array = [NSArray arrayWithObjects:#"sssss", #"hjjjjj", #"kkkkkk"];
[array retain];
[self setCode];
}
-(void)setCode
{
NSString *code = [array objectAtIndex:0];
NSLog(#"code %#",code);
[array release];
}
#end
You are declaring another object from the array inside your viewDidLoad, so your global array object will never get allocated, you need to remove the declaration as below:
-(void)viewDidLoad
{
array = [NSArray arrayWithObjects:#"sssss", #"hjjjjj", #"kkkkkk"];
int i;
[self setCode];
}
And by the way the setCode doesn't do anything rather than printing!, you can change its name to printCode.
Add
#interface PeopelListViewController : UIViewController
{
NSArray *array;
}
//in my.h file
//#property(nonatomic, retain) NSArra *array;
//and #synthesize array;
just you need to Put nil at the end of your NSArray.
such like
self.array = [NSArray arrayWithObjects:#"sssss", #"hjjjjj", #"kkkkkk", nil];
first you declare an array in implementation (.m file) like this
#implementation : myviewcontroller {
NSArray *array;
}
then initialize it like
array = [NSArray arrayWithObjects:#"sssss", #"hjjjjj", #"kkkkkk", nil];
it must work
What you did is to create a reference - local, here in this method.
-(void)viewDidLoad
But in your -(void)setCode method, you are accessing your global variable .
The global variable is not yet allocated a memory, neither initialized hence the error.
So you need to understand the scope of variables. Local scope preceeds global scope. Anyways you are working with two different array objects.
Change this in your viewDidload implementation to make it work:
// No NSArray at front that will make it an another array object
array = [NSArray arrayWithObjects:#"sssss", #"hjjjjj", #"kkkkkk"];

iOS, NSMutableDictionary

I had a problem in my project where I declared in the header file an NSMutableDictionary property like so:
#property (copy, nonatomic) NSMutableDictionary *DataDict ;
Now in the implementation file, I go ahead and initialise this dictionary because I am gonna use it, like so:
DataDict = [[NSMutableDictionary alloc]init];
Now when I did this, the minute I try to add something to this dictionary I would get this error message:
-[__NSDictionaryI setObject:forKey:]: unrecognized selector sent to instance 0x885ae60 2012-10-19 16:51:56.040 testing[2297:c07] *
Terminating app due to uncaught exception
'NSInvalidArgumentException', reason: '-[__NSDictionaryI
setObject:forKey:]: unrecognized selector sent to instance 0x885ae60'
After a while and running through my project a thousand times, I decided to uncomment my initialization line, like so
//DataDict = [[NSMutableDictionary alloc]init];
and that fixed the problem.
My question is: Why?
The problem is in the way you have defined your property. If you change it to:
#property (strong, nonatomic) NSMutableDictionary *DataDict ;
instead of copy everything should be fine.
This happens because you basically say that you want a copy of your object through your generated accessors, which returns an NSDictionary instead (an immutable copy).
You can find more on objective-c properties here.
Just as a sidenote: objective-c ivars usually start with a lowercase letter (uppercase names are used for classes), so dataDict should be preferred over DataDict.
It is because the property have "copy" attribute so NSMutableDictionary instance alloc/init-ed is "copy"'ed using "copy" method, and "copy" method create not NSMutableDictionary but NSDictionary. ("mutableCopy" will create NSMutableDictionary).
Probably, you can use "retain" instead of "copy" as attributes.
#property (retain, nonatomic) NSMutableDictionary *DataDict ;
Or, just without "copy"/"retain" but use ARC.(Automatic reference counting).
I have this exact problem. No combination of retain/copy/strong/weak, etc do the trick. What does work is to create a temporary Mutable Dictionary, load it up and then set my original equal to it.
NSMutableDictionary * tempD = [[NSMutableDictionary alloc] init];
[tempD setObject: epsTapeCut forKey:LWPrintParameterKeyTapeCut];
[tempD setObject: epsCopies forKey:LWPrintParameterKeyCopies];
[tempD setObject: epsHalfCut forKey:LWPrintParameterKeyHalfCut];
[tempD setObject: epsPrintSpeed forKey:LWPrintParameterKeyPrintSpeed];
[tempD setObject: epsDensity forKey:LWPrintParameterKeyTapeWidth];
self.ePSprintSettings = tempD;
This fails:
[self.ePSprintSettings setObject: epsTapeCut forKey:LWPrintParameterKeyTapeCut];
Declaration:
#property (nonatomic, retain) NSMutableDictionary *ePSprintSettings;
(But again, no combination of attributes makes a difference.)
Initialization:
self.ePSprintSettings = (NSMutableDictionary *)[myUserDefaults dictionaryForKey:kEpsPrintSettings];
Thank you for helping me understand.
I'm happy enough that this works, but I'd like to understand why.

Saving Arrays Between Classes

Currently attempting to save an array that is populated according to which cells in a UITableView are chosen and saving this array in an instance of a seperate object. I am getting the array to populate just fine, however, my save method, which is an IBAction that is invoked by clicking on a Bar Button doesn't seem to be working. Here is some code:
-(IBAction)saveWorkout:(id)sender {
Workouts *new = [[Workouts alloc] init];
[new addNewWorkout:customWorkout];
[customWorkout removeAllObjects];
}
This code is from the first class.
And here is the code for my addNewWorkouts method in the Workouts class:
-(void)addNewWorkout:(NSMutableArray*)array {
NSMutableArray *temp = [[NSMutableArray alloc] init];
temp = array;
self.workoutList = temp;
[temp release];
}
Here is my "Workout.h"
#import <Foundation/Foundation.h>
#interface Workouts : NSObject {
NSString *workoutName;
NSMutableArray *workoutList;
NSString *description;
int *reps;
int *weights;
int *sets;
}
#property (nonatomic, retain) NSString *workoutName;
#property (nonatomic, retain ) NSString *description;
#property (nonatomic, retain) NSMutableArray *workoutList;
-(void)addNewWorkout:(NSMutableArray*)array;
#end
Before running this code, I get a Warning from Xcode saying that 'Workouts may not respond to 'addNewWorkouts.'
Anyone know what is causing this error? Once I build & run, I click on the Save button and the app crashes with a unrecognized selector sent to instance 0x3b04410 error.
You call [new addNewWorkouts:customWorkout]
when the method's selector is addNewWorkout: (note that there is no plural in the method name)
This will make a bad method call and result in a crash.
Also, there is a problem with the memory management of the addNewWorkout method.
1- NSMutableArray *temp = [[NSMutableArray alloc] init];
2- temp = array;
3- self.workoutList = temp;
4- [temp release];
You allocate a new NSMutableArray on line 1, then lose its reference on line 2 when you replace its pointer by 'array'. The allocation you just made is lost and the program will leak.
Then, on line 4, you send a release message to 'temp' which actually points to 'array', resulting in the release of the parameter that you received and not the temporary object.
Is there a reason whny you create a temporary array? You can just assign the property and make the property copy or retain it, depending on your needs.

NSArray randomly turning into different things!

I am having a problem with memory management I think. My NSArray (called arr) is turning into different things at random times. I have no idea why. I have a .h file that that declares the array, and then I initialize the array using
NSString *input = [[NSString alloc] initWithData:myData encoding:NSACIIStringEncoding];
arr = [input componentsSeperatedByString:#"\n"];
and then I use it throughout the program and suddenly it changes into different things (UITouch, sometimes, for example). I never called a release on it. Why is it doing this? How do I prevent objects from randomly being changed due to memory issues?
Thanks!
What happens, is that the memory, once occupied by your NSArray, is occupied by another object. This may be any object, and since you're touching the screen a lot a UITouch is very common.
This means you're not retaining the NSArray when you should, so it is released prematurely. You don't show the code declaring arr, but if you declare arr as
#property (nonatomic,retain) NSArray *arr;
and synthesize it using
#synthesize arr;
then the retaining is handled by simply assiging to self.arr instead of arr:
self.arr = [input componentsSeperatedByString:#"\n"];
In cocoa-speak, your object now "owns" the array. In the dealloc method of this class, you should [self.arr release].
Should you assign some other array to self.arr, the object assigned to self.arr previously will get released, and the new one retained.
Try to retain arr.
arr = [[input componentsSeperatedByString:#"\n"] retain];
Or Initalize a new Array with this array:
arr = [[NSArray alloc] initWithArray:input];

problem related to NSString

I have 1 NSString *abc = #"Hardik";
i have NSMutableArray *array;
now i had written [array addobject:abc];
then i'm printing,NSLog(#"array = %#", array);
but i'm getting NULL
why?
I have declared NSMutableArray *array; in a.h file
i had set #property(nonatomic,retain)NSMutableArray *array;
#synthesize array;
and i have synthesize it but getting value NULL
I'm not able to understand it?
You also need to initialise your array:
array = [[NSMutableArray alloc] initWithCapacity:10];
This is pretty fundamental stuff. Have you read the "Learning Objective C Primer" yet?
It sounds like you haven't actually allocated array. Generally, you would do this in your initializer. (Don't forget to add a release to your dealloc method, too.) #synthesize creates the getter and setter, but you still have to handle allocating/deallocating the object yourself.
It sounds like your NSMutableArray* array property may not have been initialised?
Can you post your class init method?
To trigger the synthesized accessor within a class itself, you must use self. If you don't, you access the attribute's address directly bypassing the accessor methods. You need:
NSString *abc = #"Hardik";
[self.array addobject:abc];
NSLog(#"array = %#", self.array);
The reason this is important is that the synthesized methods usually also initialize the property. The internals of the synthesize array method would look something like:
-(NSArray *) array{
if (array!=nil) {
return array;
}
array=[[NSMutableArray alloc] initWithCapacity:1];
return array;
}
self.propertyName is really just shorthand for [self propertyName] and self.propertyName=someValue is just shorthand for [self setPropertyName:someValue].
Until you call self.array at least once, the array property is not initialized.
However, just to confuse things, once you have called self.array once it is initialized so you can just call array directly. So...
[self.array addObject:abc];
NSLog(#"array = %#", array);
...works while the converse would return just an empty array.
So the rules are:
Within a class implementation
(including subclasses), calling just
propertyName gives you the address
of the property but does not call
the getter/setter accessor methods.
Within a class implementation
(including subclasses), using
self.propertyName calls the
getter/setter accessor methods but
does not access attribute directly.
From outside the class
implementation e.g.
myClass.propertyName calls the
getter/setter accessor methods.