componentsJoinedByString causing crash with EXC_BAD_ACCESS - objective-c

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.

Related

Should I use defensive copies in Objective C? [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 9 years ago.
Improve this question
I was playing around with mutability, and I came up with the following code in which an immutable object can be cast to a mutable one.
- (NSString *) getaString {
NSMutableString * string = [[NSMutableString alloc] init];
[string appendString:#"This "];
[string appendString:#"was mutable."];
return string;
}
- (void)viewDidLoad {
[super viewDidLoad];
//Get a string returns an NSString, which is then cast to a mutable string with a compler warning.
NSMutableString * string = [self getaString];
[string appendString:#" And apparently still is"];
_showText.text = string;
}
or with no compiler warning
- (NSArray *) getaString {
NSMutableString * string = [[NSMutableString alloc] init];
[string appendString:#"This "];
[string appendString:#"was mutable."];
//Cast to NSString.
NSString * immutableString = string;
NSArray * array = [[NSArray alloc] initWithObjects:immutableString, nil];
return array;
}
- (void)viewDidLoad {
[super viewDidLoad];
NSMutableString * string = [[self getaString] objectAtIndex:0];
[string appendString:#" And apparently still is"];
_showText.text = string;
}
The UITextField shows the whole string of "This was mutable. And apparently still is", with no compiler warning. I've seen multiple SO posts that recommend simply casting or using mutable objects as immutable objects, but as I've just shown, that can be dangerous. Also, the cast still works without the array, but I do get a compiler warning.
My question is, should I be considering using java style defensive copies? I haven't seen any mention of defensive copies in objective C, and all I could find in Apple's documentation was a vague mention that it’s best to adopt some defensive programming practices. I'm concerned both about security and about protecting against careless coding.
The example you've given is misleading.
You are storing a NSMutableString in an array and you are taking it out. Why would you expect the string to be immutable after that?
However there are cases in which defensive copies are pretty much a standard in Objective-C.
Consider a class (let's call it CustomClass) defining a property for an NSString and a method to print it:
#property (nonatomic, strong) NSString *aString;
- (void)printTheString;
Now, since NSMutableString is a subclass of NSString, a client of this class could potentially do something like:
CustomClass *anObject = [CustomClass new];
NSMutableString *aMutableString = [NSMutableString stringWithString:#"Hey!"];
anObject.aString = aMutableString;
[anObject printTheString]; // Hey!
[aMutableString appendString:#" Got you!"];
[anObject printTheString]; // Hey! Got you!
which can be dangerous in some cases.
It has then become common practice to use the copy attribute, instead of strong, for immutable classes with a mutable subclass:
#property (nonatomic, copy) NSString *aString;
In this way a defensive copy is made when the string is assigned, preventing the client to mess with the object later on.
The previous example would then print Hey! both times.
It's also worth noting that for most of this classes sending copy to an immutable object returns the same object, instead of an actual copy. In this way you can have your cake and eat it too, since the copy will be performed only when needed.
I don't know for sure whether you should make defensive copies in Obj-c, but it is possible to make mutable copies of an immutable string, and it is possible to make immutable versions of a mutable string.
There aren't any immutable strings in your code, by the way. NSMutableStrings in an NSArray are still mutable, so you aren't doing any conversion. The array is the thing that cannot have objects appended to it.
Here's why: The array is just holding a pointer to the NSMutableString, not the actual object, so you're not changing the contents of the array by changing the contents of the string, because the memory address pointed to by the array stays the same.
Example:
NSString *original = #"Hello, world!";
// putting the original in a mutable string
NSMutableString *copy = [original mutableCopy];
NSArray *array = [NSArray arrayWithObjects:copy, nil];
// the object in the array can still be modified
[[array objectAtIndex:0] appendString:#" Goodbye, cruel world!"];
// make an immutable version of the mutable string
NSString *copyOfTheCopy =[NSString stringWithString:[array objectAtIndex:0]];
NSLog(#"%#", [array objectAtIndex:0]);
// just to make sure...
[[array objectAtIndex:0] appendString:#"Got you!"];
NSLog(#"%#", [array objectAtIndex:0]);
NSLog(#"%#", copyOfTheCopy);
The output should be:
2013-11-03 21:16:06.099 SomeProject[7045:303] Hello, world! Goodbye, cruel world!
2013-11-03 21:16:06.100 SomeProject[7045:303] Hello, world! Goodbye, cruel world!Got you!
2013-11-03 21:16:06.100 SomeProject[7045:303] Hello, world! Goodbye, cruel world!
Another answer given by Gabriele Petronella caused me to make a change that gets rid of one of those gotchas with pointers. This one doesn't use a pointer to the NSMutableString and instead makes a new string from the old one. Sorry I can't vote you up yet, you taught me something :)
If you're looking to obtain an immutable NSString from an NSMutableString, you can do something like this:
NSString *anImmutableString = [NSString stringWithString: aMutableString];
So if we take your original code in the question, and I'm going to assume that your viewDidLoad is where you want an immutable string:
- (NSArray *) getaString {
NSMutableString * string = [[NSMutableString alloc] init];
[string appendString:#"This "];
[string appendString:#"was mutable."];
NSArray * array = [[NSArray alloc] initWithObjects:string, nil];
return array;
}
- (void)viewDidLoad {
[super viewDidLoad];
NSString *string = [NSString stringWithString:[[self getaString] objectAtIndex:0]];
//[string appendString:#" And apparently still is"];
_showText.text = string;
}
Now, if you still want to append to string in viewDidLoad, you can, but you'd have to do it differently (the same way you append to any other NSString). It'd look something like this:
NSString *newString = [string stringByAppendingString:#" And apparently still is"];
Now look at the contents of the variables.
string = "This was mutable." //as you built it from an NSMutableString in the getaString method
newString = "This was mutable. And apparently still is" //as built from calling "stringByAppendingString" method on your variable string in viewDidLoad
It's important to note that the contents of newString are quite misleading here. newString is not an NSMutableString. It's a regular NSString. Calling stringByAppendingString returns an NSString that is the result of appending the argument you send to the end of the NSString you're calling the method on. (And the contents of the NSString you called the method on remain unchanged--it's immutable).
If you would like newString to be an NSMutableString, you'll have to do something like this:
NSMutableString *newString = [[string stringByAppendingString:" And apparently still is"] mutableCopy];

understanding mutable copy

Due to an example from Apress,for a search criteria,it has a soultion:it will firstly get a mutable copy and search the string and then will remove objects that are not in range of that string.
in the Mutable DeepCopy it has function as follow:
#implementation NSDictionary(MutableDeepCopy)
-(NSMutableDictionary *)mutableDeepCopy{
NSMutableDictionary *returnDict=[[NSMutableDictionary alloc]initWithCapacity:[self count]];
NSArray *keys=[self allKeys];
for(id key in keys)
{
id oneValue=[self valueForKey:key];
id oneCopy=nil;
if([oneValue respondsToSelector:#selector(mutableDeepCopy)])
oneCopy=[oneValue mutableDeepCopy];
else if([oneValue respondsToSelector:#selector(mutableCopy)])
oneCopy=[oneValue mutableCopy];
if(oneCopy==nil)
oneCopy=[oneValue copy];
[returnDict setValue:oneCopy forKey:key];
}
return returnDict;
}
#end
when I don't understand any code I will debug it,so I debugged it and in the beginnings when it wants to show the whole array,in the if statement it will go to oneCopy=[oneValue mutableCopy]; I want to know that why it will choose this selector and not the MutableDeep selector? I can't understand this function totally.what is the main purpose of this function?
for searching it has this function
-(void)handleSearchForTerm:(NSString *)searchTerm
{
NSMutableArray * sectionsToRemove=[[NSMutableArray alloc]init];
[self resetSearch];
for(NSString * key in self.keys)
{
NSMutableArray * array=[names valueForKey:key];
NSMutableArray *toRemove=[[NSMutableArray alloc]init];
for(NSString * name in array)
{
if([name rangeOfString:searchTerm options:NSCaseInsensitiveSearch].location==NSNotFound)
[toRemove addObject:name];
}
if([array count]==[toRemove count])
[sectionsToRemove addObject:key];
[array removeObjectsInArray:toRemove];
}
[self.keys removeObjectsInArray:sectionsToRemove];
[table reloadData];
}
and for reset the search and recovering whole it has this function below.
my problem is that in self.keys we removed objects with help of handleSearchForTerm but when we go to resetsearch it will return again those whole keys without any removal maybe my main problem is that I can't understand Mutablecopy and DeepMutableCopy.
-(void)resetSearch{
NSMutableDictionary *allNamesCopy=[self.allNames mutableDeepCopy];
self.names=allNamesCopy;
NSMutableArray *keyArray=[[NSMutableArray alloc]init];
[keyArray addObjectsFromArray:[[self.allNames allKeys]sortedArrayUsingSelector:#selector(compare:)]];
self.keys=keyArray;
}
They both have some compare & contrast features...
First comparing: Both are mutable, you can alter the object itself.
Second contrasting/differences:
MutableCopy: Similar to Call-by-Reference.
MutableDeepCopy: Similar to Call-by-Value.
A copy of a container (e.g. NSArray) copies only the pointers to objects and sends them retain.
A mutableCopy does the same thing, but the resulting container can be modified, i.e. Pointers can be added or removed.
A deep copy would also make copies of the individual elements.
Take for example an NSArray of NSMutableString instances. You cannot modify the array itself, but you can alter each mutable string. Now if you copy the array and modify one of the strings then the copied array also has the changes because it's pointers point to the same instances as the first array.
If you deep copy the array and alter a mutable string, then the new array elements are not modified. In fact copy always makes an immutable copy.

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.

Objective C - EXC_BAD_ACCESS on [NSArray count] but can't see how

I'm working on a piece of code that GETs a URL and parses the contents for data between a asset of tags. In this case, it's looking for the code between and . When the URL body returned doesn't contain those tags, the cullXML: method returns an empty array like this:
return [NSArray arrayWithObjects: nil];
I check to be sure that the returned array has objects with:
if ( matchesXML.count ) {
In my debug code, I check twice. The first time, it works fine. The second time, just a couple lines later, it crashes. I can't see why. The lines look the same to me.
What am I missing?
A bigger chunk of the code is included below. Thanks!
if (self.newResults) {
NSString *urlResult;
NSArray *matchesXML;
NSArray *match;
NSDictionary *currentResult;
NSMutableDictionary *results = [[NSMutableDictionary alloc] init];
NSArray *returnedObjects;
NSArray *dictionaryKeys;
NSMutableArray *currentResultObjects;
int i = 0;
// determine tournament type, because the fields are different per type
NSString *tournamentType;
tournamentType = [[AFMethods tournamentTypeFromId:self.inputTournamentId] objectAtIndex:0];
urlResult = [NSString stringWithFormat:#"%#", responseHandle];
[responseHandle release];
NSLog(#"urlResult retrieved: %#", urlResult);
matchesXML = [AFMethods cullXML: urlResult forTag: #"matches"];
NSLog(#"matches loaded: %#", matchesXML);
NSLog(#"matchesXML.count %i", matchesXML.count);
if ( matchesXML.count ) {
NSLog(#"not nil");
}
NSLog(#"just before tested");
if ( matchesXML.count ) {
NSLog(#"tested");
I found the issue!
It wasn't crashing where I thought. It was a couple lines later. I was releasing an auto-released object. It must have been a left-over line from a previous organization of the code.
I removed the release and it's working perfectly again.
My guess is that you're not using the return statement you listed, but rather one that returns a different NSArray, only this one isn't retained. The first NSLog causes heap to be used, stomping on the array object.

How am I meant to release an array returned from a class method?

I have a section of my code which calls a method returning an NSMutableArray like so:
+(NSMutableArray *)method {
NSMutableArray *rgb = [[NSMutableArray alloc] initWithObjects:....., nil];
return rgb;
}
It gives me a leak every time it's called. Putting [rgb release]; after return doesn't appear to work. Putting it before return makes my app crash. Also putting in an autorelease makes my app crash. Suggestions?
+(NSMutableArray *)method {
NSMutableArray *rgb = [[NSMutableArray alloc] initWithObjects:....., nil];
return [rgb autorelease];
}
Alternatively:
+(NSMutableArray *)method {
NSMutableArray *rgb = [NSMutableArray arrayWithObjects:....., nil];
return rgb;
}
IF this still crashes, then the problem is most likely outside of that method, not within.
But this gives me a leak every time
it's called. Putting a [rgb release];
after return doesn't appear to work.
putting it before return makes my app
crash. Also putting in an autorelease
makes my app crash. Suggestions?
You need to read the Cocoa Memory Management Guidelines. It makes it quite clear that such a method as that must autorelease the returned object:
+(NSMutableArray *)method {
NSMutableArray *rgb = [[NSMutableArray alloc] initWithObjects:....., nil];
return [rgb autorelease];
}
Or, alternatively:
+(NSMutableArray *)method {
NSMutableArray *rgb = [NSMutableArray arrayWithObjects:....., nil];
return rgb;
}
An over-retain (like in your code) will not cause a crash (at least not until you run out of memory). If you have a crash, it is most likely because your are mismanaging memory in other ways.
Try using Build and Analyze and fixing all of the issues it identifies. If it still crashes, post the backtrace of the crash if you can't figure out why.