replaceObjectAtIndex:withObject does not work - objective-c

I am trying to assign objects in an NSMutableArray using this code
- (IBAction)variablePressed:(UIButton *)sender {
NSString *variable = [sender currentTitle];
if (!_variableToBePassedIntoTheDictionary) _variableToBePassedIntoTheDictionary = [[NSMutableArray alloc] init];
[_variableToBePassedIntoTheDictionary replaceObjectAtIndex:0 withObject:variable];}
but when I run this program the program breaks at the last line, since I have set the debugger to show warnings if a Exception is raised. Running the program without breakpoints, the program gives SIGARBT and crashes. I then assign these values to a dictionary which would be passed to the Model for further calculations.
- (IBAction)testVariableValues:(id)sender {
if (!_variablesAssignedInADictionary) _variablesAssignedInADictionary = [[NSMutableDictionary alloc] init];
[_variablesAssignedInADictionary setObject:_digitToBePassedIntoTheVariable forKey:_variableToBePassedIntoTheDictionary];
NSLog(#"%#", _variablesAssignedInADictionary);}
P.S. I am new in Objective C, can anybody please explain when do we use
#synthesize someProperty;
vs
#synthesize someProperty = _someProperty;
Thank You!

The first time the method is called you create the NSMutableArray and then attempt to replace an object which is not there. The reference says:
- (void)replaceObjectAtIndex:(NSUInteger)index withObject:(id)anObject
The index of the object to be replaced. This value must not exceed
the bounds of the array. Important Raises an NSRangeException if
index is beyond the end of the array.
And 0 will exceed the bounds of an empty array.
Try this instead:
- (IBAction)variablePressed:(UIButton *)sender
{
NSString *variable = [sender currentTitle];
if (_variableToBePassedIntoTheDictionary == nil)
{
_variableToBePassedIntoTheDictionary = [[NSMutableArray alloc] init];
[_variableToBePassedIntoTheDictionary addObject:variable];
}
else
{
[_variableToBePassedIntoTheDictionary replaceObjectAtIndex:0 withObject:variable];
}
}

Taken from the docs :
The index of the object to be replaced. This value must not exceed the
bounds of the array.
As I see from your code your array is initialized and there is no object at index 0. hence you try to replace an object at an index which is out of bounds as your array is empty.

Very simple question:
You told it stops on an exception. Fair enough. What for an exception? Let me guess, an out of bounds exception? The exception tells you what's wrong in most cases.
replaceObjectAtIndex:0 : is there something at that index or not? Probably not.

In your code you test the condition:
if(!_variableToBePassedIntoTheDictionary)
and if the condition is true, that is the array is nil, then you alloc-init it.
In the following statement:
[_variableToBePassedIntoTheDictionary replaceObjectAtIndex:0 withObject:variable];,
you try to replace the object at index 0 with variable. But in the case above, if you just alloc-init the array, it is empty and than you cannot replace the object at index 0 as not existing, and this raises an exception:
*** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSArrayM replaceObjectAtIndex:withObject:]: index 0 beyond bounds for empty array'
So what you have to do is to change the last line as follows:
if([_variableToBePassedIntoTheDictionary count]==0) {
[_variableToBePassedIntoTheDictionary addObject:variable]
} else {
[_variableToBePassedIntoTheDictionary replaceObjectAtIndex:0 withObject:variable]
}
As far as the second question about properties, consider that the role of synthesize is to create for you the setter/getter methods based on the attributes you assigned to the #property. In the new Objective-C you don't need to declare the ivar associated to the property (the ivar is the instance variable that represent the property) and the compiler by default assigns the ivar the name of the property. By using the
#synthesize someProperty = _someProperty
convention you specify that you want the ivar to be called _someProperty. The advantage of this approach with respect to the default one is that you cannot confuse accessing to a property using the setter/getter methods and the ivar directly, that is you cannot make possible mistakes like:
someProperty=value
but instead you must write:
_someProperty=value
or
self.someProperty=value
Anyway have a look at Obj-C documentation for this, it is quite exhaustive.

Related

Objective-C Changing values of instance variables in method

I am write a Objective-C Code on XCode 4.4.
I have a NSMutableArray as a instance variable of my class k_info
I have defined and synthesized (nonatomic,retain) property by the name of onesplaces too.
I am unable to add a NSMUtableString object in the NSMutableArray onesplaces.
When I try to add it.The size of onesplaces remains 0 and object at zero index obviously remains null.
I tried doing this with and without using "self" key-word but it didnt worked in either case.
My syntax of adding object and printing it is right because when I create a new NSMutableArray test
and try to do the same thing it works for it but not for the instance variable onesplaces.
I cannot proceed any further in my project without solving this issue.please tell me why is it
happening and how should I solve this problem.
-(void)createinfo:(NSMutableArray )al varsis:(int)vars
{
NSMutableString stes=[[NSMutableString alloc]init];
stes=(NSMutableString*)#"string0";
[ onesplaces addObject:stes];
NSLog(#"%u",[onesplaces count]);
NSLog(#"value is: %# ",[ onesplaces objectAtIndex:0]);
[ self.onesplaces addObject:stes];
NSLog(#"%u",[onesplaces count]);
NSLog(#"value is: %# ",[self.onesplaces objectAtIndex:0]);
NSMutableArray* test=[[NSMutableArray alloc]init];
[ test addObject:stes];
NSLog(#"%u",[test count]);
NSLog(#"value is: %# ",[test objectAtIndex:0]);
}
You probably forgot to create the array. Somewhere in your code, maybe in your init method, you need to create the array before using it.
self.onesplaces = [[NSMutableArray alloc] init];
You get nil instead of error messages because Objective-C allows you to send messages to nil, which always return nil.

Is myiVar = nil supported in ARC?

I'm using a code snippet like
if ([Array count] != 0) {
Array = nil;
}
Array = [[NSMutableArray alloc]init];
Is this allowed when using ARC? Does this cause any kind of crashes? Why I'm doing this is each time when my method gets called Array gets a new set of data. I'm using this kind of snippet in many places of my class.
ARC aside, the operation is pointless. You assign an ivar to nil then immediately assign to something else. This is no different from just assigning it to the something else.
Before ARC this would have given you a memory leak (with or without your assignment to nil) if there variable had a previous value. With ARC there is no leak.
Best solution : test and see by yourself ! This is a really short example !
But yes, this works of course !
ARC means Automatic Reference Counting. It just says you don't have to care about release, retain and so on.
If you want an object to be nil, you still can, as it is a simple pointer assignment !
And about your code, you set Array to nil before re-assigning it oO !
Try to get the logic of your code :
If my Array has objects
Then Array point to a new nil object
But in all case you do:
My Array point to a new NSMutableArray object
So whether or not your condition is evaluated to true, your code is useless as the variable will take another value just after !
The sample code you showed is valid. Here are a few variations:
if ([Array count] != 0) {
Array = [[NSMutableArray alloc] init];
}
Example 2:
if ([Array count] != 0) {
Array = [NSMutableArray array]; //value will be retained
}
Example 3:
if ([Array count] != 0) {
self.Array = [[NSMutableArray alloc] init]; //Will NOT leak under ARC.
}
Example 4:
//if ([Array count] != 0) {
[Array removeAllObjects];
//}
All four examples are valid under ARC.
Another thing: instance variables typically have their first letter lowercase, while still following the CamelCase method. Another way to do it is to have an underscore before the name of the variable: this is done if you don't have a #synthesize method to match your #property value.

big memory problem in objective c

i've a function like this:
#property(nonatomic,retain) NSMutableArray *array;
#synthesize array = _array;
(NSMutableArray *) name
{
self.array = [[NSMutableArray alloc]init];
[_array addObject:object];
[object release];
return [_array autorelase];
}
In the other function i've a property like the property above, named result, and i make:
self.result = [... name];
Then in dealloc i make
[_result release];
and it crashes in this point, how can i solve this?
I've tried many roads, but or it crashes, or i see memory leak in Instruments, where am i wronging?
Thanks.
While there's a lot wrong with this code, the likely cause of your crash is that you're releasing object within -name without taking ownership of it- unless you're creating object within the method through a call to -alloc, -new, or -copy, that method doesn't own it and isn't responsible for releasing it. This is causing that object to be invalid within the NSMutableArray, so when _result releases, it attempts to release an invalid piece of memory and crashes.
Also, properties aren't simply local variables for individual functions, they're member variables for instances of the class for which you're writing these classes. If your end goal is only to return an autoreleased array and set it to result you could do the following:
- (NSMutableArray *) name {
//call a convenience method- it comes back autoreleased
NSMutableArray* theArray = [NSMutableArray array];
[theArray addObject:object];
//don't release object unless you took ownership of it in this function
return theArray;
}
then outside the function, either call self.result = [... name] or [self setResult:[... name]];
You have a very strange method definition (the header should have a - before the return type), and inside that definition you are accessing a variable called object that doesn't seem to exist. I'm not sure what you want, but you've got at least one memory problem. The array that you create in name gets leaked every time the method is called. If you add some details, like the crash message, someone may be able to help more.

NCSFDictionary, Mutating method sent to immutable object

I have just started to jump into the realm of Objective-C and am slowly getting it all. I have been working on unarchiving a file that was a NSMutableArray and then initializing in my model with that array. The array is filled with various NSMutableDicationary's. From what I have seen it will add those dictionaries as non-mutable, so I went ahead and copied the regular and put them in a mutable and remove the old one. This solution seems to work for every instance except the very first.
I am at a loss as to why it would work for all but the first.
Here is how I am initializing it all
-(id) initWithList:(NSMutableArray *)savedList
{
self = [super init];
if (self)
{
int size=0;
serverList=[[NSMutableArray alloc] initWithArray:savedList copyItems:YES];
size=[serverList count];
for(int i=0;i<size;i++)
{
loginList=[NSMutableDictionary dictionaryWithDictionary:[serverList objectAtIndex:i]];
[serverList addObject:loginList];
[serverList removeObjectAtIndex:i];
}
}
return self;
}
Here is the code that is throwing the error, The value is being read off of a checkbox in a tableview and passed here to change the value.
-(void)setMount:(int)row value:(NSNumber*)boolAsNumber
{
[[serverList objectAtIndex:row] setObject:boolAsNumber forKey:#"mountshare"];
}
Here is the error that it shows when I try and change the first element
2010-12-01 13:38:54.445 Network Share[35992:a0f] *** -[NSCFDictionary setObject:forKey:]: mutating method sent to immutable object
Thanks for your help. If there is a better way please let me know.
This loop code is wrong:
size=[serverList count];
for(int i=0;i<size;i++)
{
loginList=[NSMutableDictionary dictionaryWithDictionary:[serverList objectAtIndex:i]];
[serverList addObject:loginList];
[serverList removeObjectAtIndex:i];
}
When you remove an object, the array is renumbered. After you've processed the 1st object at index 0, the original 2nd object is becoming the 1st object at index 0, but i is now set to index 1, which is where the original 3rd object is! This means you're only processing alternate items from the original array, and the 2nd, 4th, etc items never get swapped, and that's why you get the errors you're seeing.
One way to solve this would be to replace the "i" in the objectAtIndex: and removeObjectAtIndex: calls with "0", so you're always taking items off the front of the array.
The alternate solution would be to create a separate newServerList array and insert your new objects into that. At the end of the loop, release the old serverList and set the variable to point to newServerList.
Your indexes are messed up. As soon as you remove the object at index 0, the next one will take it's place and you will never replace that, because you then carry on with index 1.
{immutable0, immutable1}
i = 0:
addObject:
{immutable0, immutable1, mutable0}
removeObjectAtIndex:
{immutable1, mutable0}
i = 1:
addObject:
{immutable0, mutable0, mutable02}
removeObjectAtIndex:
{immutable0, mutable02}
--> still got the immutable there. Remember to never remove objects from a mutable array you are looping through at the same time.
You could condense the code a bit:
NSMutableArray *serverList = [NSMutableArray arrayWithCapacity:[savedList count]];
for (NSDictionary *dictionary in savedList)
{
mutable = [dictionary mutableCopy];
[serverList addObject:mutable];
[mutable release];
}
Unrelated to your problem: the argument is obviously wrong (NSMutableArray), if you expect an immutable array there; and if you create your serverList that way, there is no need for a deep copy (copyItems:YES).

Is if (variable) the same as if (variable != nil) in Objective-C

I am getting a EXC_BAD_ACCESS (SIGBUS) on this line in my iPhone project:
if (timeoutTimer) [timeoutTimer invalidate];
The thing that has me stumped is that I don't understand how that line could crash, since the if statement is meant to be checking for nil. Am I misunderstanding the way Objective-C works, or do line numbers in crash statements sometime have the wrong line in them?
Just because a variable is set to a value other than nil doesn't mean it's pointing to a valid object. For example:
id object = [[NSObject alloc] init];
[object release];
NSLog(#"%#", object); // Not nil, but a deallocated object,
// meaning a likely crash
Your timer has probably already been gotten rid of (or possibly hasn't been created at all?) but the variable wasn't set to nil.
I just ran into a similar issue, so here's another example of what might cause a check such as yours to fail.
In my case, I was getting the value from a dictionary like this:
NSString *text = [dict objectForKey:#"text"];
Later on, I was using the variable like this:
if (text) {
// do something with "text"
}
This resulted in a EXC_BAD_ACCESS error and program crash.
The problem was that my dictionary used NSNull values in cases where an object had an empty value (it had been deserialized from JSON), since NSDictionary cannot hold nil values. I ended up working around it like this:
NSString *text = [dict objectForKey:#"text"];
if ([[NSNull null] isEqual:text]) {
text = nil;
}
They should be the same. Perhaps the line number is in fact incorrect.
Look for other possible errors near that in your code and see if you find anything.