A bug with NSMutableArray of NSString? - ios

NSString *str = #"1 2 3 4 5";
NSMutableArray *strArray = [[[str componentsSeparatedByString:#" "] mutableCopy] autorelease];
[strArray removeObjectAtIndex:3];
[strArray removeObjectAtIndex:0];
At the end of this code I expect that array contains #"2", #"3", #"5".
But it contains 0x00000, #"2", #"3".
How to fix it? Numbers are for example only, there could be various strings of various length separated with spaces.
UPDATED
It is strange, but it really writes 2, 3, 5 into console.
But here is the same array in debug window:

Not sure why your code is not working its working fine for me, also tried the same in other way below :-
NSString *str = #"1 2 3 4 5";
NSArray *arr1= [str componentsSeparatedByString:#" "];
NSMutableArray *strArray=[NSMutableArray arrayWithArray:arr1];
[strArray removeObjectAtIndex:3];
[strArray removeObjectAtIndex:0];
NSLog(#"%#",strArray);
Output:-
2
3
5

Here is what I think is happening. What you have is, if anything, a bug in the debugger.
Let's assume for the moment that NSMutableArray is represented by a normal C array internally. The naive implementation of -removeObjectAtIndex: would shuffle up all the objects after the one you want to remove into the previous slot in the array. This has O(n) complexity, where n is the number of objects in the array.
An optimisation might be to associate a "base index" with the array which will be subtracted from the index supplied to any method that takes an index as a parameter. That way, [foo removeObjectAtIndex: 0] can be implemented by simply assigning nil to the first element and bumping the base index for constant time complexity.
I'm sure the real implementation is more complex than that, but the above just serves to illustrate the idea.
If the debugger doesn't know about this, it would display the underlying C array exactly as it does in the screen cap your question. The point is that you can't really trust the debugger on anything where it can't be expected to know the internals of the object. Printing the description to the console is a much more reliable method of examining the object - as long as -description has a helpful implementation.

Why aren't you using ARC? I have tested that code using ARC and it works. So, can you explain it a little bit more what you are trying to do? (I could't added it as comment)

remove your autorelease! Fine working for me!
NSString *str = #"1 2 3 4 5";
NSMutableArray *strArray = [[str componentsSeparatedByString:#" "] mutableCopy];
[strArray removeObjectAtIndex:3];
[strArray removeObjectAtIndex:0];
NSLog(#"strArray = %#", strArray);
2013-10-16 14:29:35.537 Notes[566:c07] strArray = (
2,
3,
5
)

Related

Find difference between two comma separated NSMutableString

Suppose I have two NSMutableString like this:-
String 1 ----- {aaa,bss,cdd,dff,eee,fgh}
String 2 ----- {aaa,bss,cdd}
How can we find the the difference between String 1 & String 2 in an NSArray:-
Like this:- { dff,eee,fgh }
As mentioned in duplicate question it is different.
Put both these strings in two different NSMutableSets and then subtract 2nd from 1st.
You will have your result.
NSString* str1 = #"aaa,bss,cdd,dff,eee,fgh";
NSString* str2 = #"aaa,bss,cdd";
NSMutableSet *set1 = [NSMutableSet setWithArray:[str1 componentsSeparatedByString:#","]];
NSMutableSet *set2 = [NSMutableSet setWithArray:[str2 componentsSeparatedByString:#","]];
[set1 minusSet:set2];
NSLog(#"result %#",[set1 allObjects]);
Try with NSMutableArray to remove same objects.
For Eg.
NSString *s1 = #"aaa,bss,cdd,dff,eee,fgh";
NSString *s2 = #"aaa,bss,cdd";
NSArray *arr1 = [s1 componentsSeparatedByString:#","];
NSArray *arr2 = [s2 componentsSeparatedByString:#","];
NSMutableArray *resArray = [NSMutableArray arrayWithArray:arr1];
[resArray removeObjectsInArray:arr2];
NSString *res = [resArray componentsJoinedByString:#","];
NSLog(#"Result :: %#", res);
Hopefully, it'll help you.
Thanks.
First part of the problem is to separate each string into substrings separated by the commas.
To create the substrings you can use
[string substringFromIndex:index] - to get an NSString from that index foward
[string substringToIndex:index] - to get an NSString from the begining to that index
Or you could combine it into
[string substringWithRange:NSMakeRange(fisrtIndex, secondIndex)] - to get a strin from the first index to the second index
Those are the basic operations. But there are a lot more in this case you could use specifically:
[string componentsSeparatedByString:#","] to get an NSArray with all the substrings. That would have the problem of the '{' and '}' appearing in the first and last component. This can be solved in many ways:
by first trimming the string using the substring methods already explained
by using another method altogether
[string componentsSeparatedByCharactersInSet: [NSCharacterSet characterSetWithCharactersInString:#",{"]] The problem with this method is, because your strings start/end with one of the separators you would get the first/last component an empty string. You can just remove it from the array or ignore it or choose the other method, your choice.
Now that you know how to get the substrings all you need to know is how to compare the two. There are literally many ways to do this. I am just going to name a few. Of course each solution has its own advantages and disadvantages and code complexity.
1 - comparing each substring one by one the the other using isEqualToString:
2 - comparing each substring from one of the original strings with the full second original string by using [string2 rangeOfString:substring].location != NSNotFound
3 - if you have iOS 8 or OS X Yosemite you can use [string2 containsString:substring]
4 - You can transform the arrays of substrings into sets and then compare them as Ankit Srivastava suggested
5 - You can use the removeObjectsInArray to get the substrings that are not common between the two and then use that newly created array to removeObjectsInArray to the original and have just the common...
Really the possibilities are almost endless

Separate a string into different Array

I have a string coming from server , i want to show some part of string in a view and rest part of string in other view .
Thanks for help.
i want to get the last word of last line of first view. i have searched ,but nothing seems to help me. If any one can suggest me something i would be glad to him/her.
NSString *fromIndex = [_categoryWiseNews.article substringWithRange:NSMakeRange(0, lastWordOfFirstView)];
i have tried with substringWithRange but with this you have to know the lastWordOfFirstView index number for breaking the string into two parts, for which i have no idea.
I really don't know what it is that you're asking lastWordOfFirstView might make sense to you because it is relevant to the thing you are working on. But to us it means nothing.
You can separate a string into words in an array doing this...
NSString *string = #"Hello world, this is a string";
NSArray *array = [string componentsSeparatedByString:#" "];
// array is now... [#"Hello", #"world,", #"this", #"is", #"a", #"string"];
Then you can get the last word from it...
NSString *lastWord = [array lastObject];
Use this to get the last word from a sentence:
NSString *lastWord = [[fullSentenceString componentsSeparatedByString:#" "] lastObject];

NSArray componentsJoinedByString with condition

For example, I have an array
NSArray *array = [NSArray arrayWithObjects:#"one<true>",#"two<false>",#"three<true>",#"four<false>"];
I want the output as NSString using componentsJoinedByString
"one<true>'&'two<false>'&&'three<true>'&'four<false>'&&'"
That is, in an array if an object contain a value <true> it should be joined by '&' and if an array value contain a value <false> it should be joined by '&&'.
I know, I can run a for loop and using if condition, I can achieve the output. But I'm looking for other efficient way to implement this.
Thanks in advance.
It may be help
you can use stringByReplacingOccurrencesOfString
for ex:
yourArrayJoinString=[yourArrayJoinString stringByReplacingOccurrencesOfString:#"<true>" withString:#"<true>'&'"];
yourArrayJoinString=[yourArrayJoinString stringByReplacingOccurrencesOfString:#"<false>" withString:#"<false>'&&'"];
Try with this
NSArray *array = [NSArray arrayWithObjects:#"one<true>",#"two<false>",#"three<true>",#"four<false>" ,nil];
NSString *str = [array componentsJoinedByString:#""];
str =[str stringByReplacingOccurrencesOfString:#"<false>" withString:#"<false>'&&'"];
str =[str stringByReplacingOccurrencesOfString:#"<true>" withString:#"<true>'&'"];

Objective C Array Count String Issue

Okay I am new to objective C and am trying hard to learn it on my own with out bother the stacked overflow community to much but it is really quite different then what I'm used to (C++).
But I have come across a issue that I for the life of me can't figure out and I'm sure it's going be something stupid. But I am pulling questions and answers from a website that then will display on my iOS application by using this code.
NSString * GetUrl = [NSString stringWithFormat:#"http://www.mywebpage.com/page.php"];
NSString * GetAllHtml = [NSString stringWithContentsOfURL:[NSURL URLWithString:GetUrl] encoding:1 error:nil];
NSString *PullWholeQuestion = [[GetAllHtml componentsSeparatedByString:#"<tr>"] objectAtIndex:1];
NSString *FinishWholeQuestion = [[PullWholeQuestion componentsSeparatedByString:#"</tr>"] objectAtIndex:0];
After I get all of the webpage information I strip down each question and want to make it where it will do a loop process to pull the questions so basically I need to count how many array options there are for the FinishedWholeQuestion variable
I found this snippet online that seemed to work with there example but I cant repeat it
NSArray *stringArray = [NSArray arrayWithObjects:#"1", #"2", nil];
NSLog(#"count = %d", [stringArray count]);
"componentsSeparatedByString" returns an NSArray object, not a single NSString.
An array object can contain zero, one or more NSString objects, depending on the input.
If you change "FinishWholeQuestion" into a NSArray object, you'll likely get a few components (separate by a string).
And now that I'm looking at your code a little more closely, I see you're making an assumption that your array is always valid (and has more than 2 entries, as evidenced by the "objectAtIndex: 1" bit).
You should also change the first character of all your Objective-C variables. Best practices in Objective-C are that the first character of variables should always be lower case.
Like this:
NSString * getUrl = [NSString stringWithFormat:#"http://www.mywebpage.com/page.php"];
NSString * getAllHtml = [NSString stringWithContentsOfURL:[NSURL URLWithString:getUrl] encoding: NSUTF8StringEncoding error:nil];
NSArray * allQuestions = [getAllHtml componentsSeparatedByString:#"<tr>"];
if([allQuestions count] > 1)
{
// assuming there is at least two entries in this array
NSString * pullWholeQuestion = [allQuestions objectAtIndex: 1];
if(pullWholeQuestion)
{
NSString *finishWholeQuestion = [[pullWholeQuestion componentsSeparatedByString:#"</tr>"] objectAtIndex:0];
}
}

ios: Retain count of 2147483647? [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicates:
NSString retainCount is 2147483647
Objective C NSString* property retain count oddity
Have a look at the following code:
NSString* testString = [[NSString alloc] initWithString:#"Test"];
NSLog(#"[testString retainCount] = %d", [testString retainCount] );
NSMutableArray* ma = [[NSMutableArray alloc] init];
[ma insertObject:testString atIndex:0];
[testString release];
NSLog(#"%#", [ma objectAtIndex:0]);
This is the output on the console :
[testString retainCount] = 2147483647
Test
How can this happen? I expected 1 not 2147483647!
You initiate your NSString object with string literal and 2 following things happen:
As NSString is immutable -initWithString: method optimizes string creation so that your testString actually points to a same string you create it with (#"Test")
#"Test" is a string literal and it is created in compile time and lives in a specific address space - you cannot dealloc it, release and retain does not affect its retain count and it is always INT_MAX
With all mentioned above you still should work with your string object following memory management rules (as you created it with alloc/init you should release it) and you'll be fine
You can only have two expectations for the result of retainCount:
1) It's greater than 1. You cannot predict what number it will actually be because you don't know who else is using it. You don't know how somebody else is using it. It's not a number you should care about.
2) People will tell you not to use it. Because you shouldn't. Use the rules to balance your retains and releases. Do not use retainCount. It will frustrate and confuse you, for no value.

Resources