NSMutable Array High CPU Usage - ios

I recently change c array to NSMutable array because I had a lot of troubles with memory. However it works, but starting from
/* If two starttimes are within interval millisec, make them the same */
for (int i = 0; i < [starttimes count] - 1; i++) {
if ([[starttimes objectAtIndex:i+1] integerValue] - [[starttimes objectAtIndex:i] integerValue] <= interval) {
[starttimes insertObject: [starttimes objectAtIndex:i] atIndex:(i+1)];
}
}
CPU usage is nearly 100%. I do not know what is going on? The logic is fairly simple. All it does is to get two elements from this NSMutable array, then compare and insert. BTW, this chunk of codes never stop. It keeps running 3 seconds, then my app crashes.
(TimeSignature*)time {
/* Get all the starttimes in all tracks, in sorted order */
NSInteger initsize = 1;
if ([tracks count] > 0) {
MidiTrack *track = [tracks objectAtIndex:0];
initsize = [track.notes count];
initsize = initsize * [tracks count]/2;
}
NSMutableArray* starttimes = [[NSMutableArray alloc]initWithCapacity:initsize];
for (int tracknum = 0; tracknum < [tracks count]; tracknum++) {
NSLog(#"tracknum is %d",tracknum);
MidiTrack *track = [tracks objectAtIndex:tracknum];
NSLog(#"WE ARE HERE %ld",(long)initsize);
for (int j = 0; j < [track.notes count]; j++) {
MidiNote *note = [track.notes objectAtIndex:j];
NSLog(#"%#",note);
[starttimes addObject:[NSNumber numberWithInteger:note.startTime]];
}
}
/* Notes within "millisec" milliseconds apart should be combined */
int interval = time.quarter * millisec * 1000 / time.tempo;
/* If two starttimes are within interval millisec, make them the same */
for (int i = 0; i < [starttimes count] - 1; i++) {
if ([[starttimes objectAtIndex:i+1] integerValue] - [[starttimes objectAtIndex:i] integerValue] <= interval) {
[starttimes insertObject: [starttimes objectAtIndex:i] atIndex:(i+1)];
}
}
Thanks so much

General Objective-C advice: read the method names. They tell you want the methods do.
You've misunderstood -insertObject:. What insertObject does is... insert an object. What it does not do: replace an object. You're increasing the size of the array every time you call insertObject. In practice you're creating an infinite loop should the if condition pass even once.
You probably wanted -replaceObjectAtIndex:withObject:. Which, like insertObject:, will do what the name says.

Related

NSNumber in arrays, ios

I am trying to learn about how to put numbers into an array with nsnumber. The exact thing I'm stuck with is, To build the sequence in the array, we're going to need a loop. Between creating the sequence array and returning it, declare a for loop whose counter is limited by index + 1 and increments by one.
Since the sequence requires the two previous numbers to calculate the next one, we need to prime the sequence. We're going to need to manually pass in #0 and #1 on the first two iterations of the loop. This is what I have so far.
(NSArray *)arrayWithFibonacciSequenceToIndex:(NSUInteger)index
{
NSMutableArray *sequence = [NSMutableArray array];
for(NSUInteger i = 0; i < 1; i++)
{
index = i+1;
}
return sequence;
}
Am I on the right track? I'm not sure if my for loop is correct. Do I put sequence into the for loop and add the nsnumber #0 and #1 there or do I put those numbers into the sequence outside the loop?
To insert a number in an NSArray, you have to wrap them in a NSNumber:
NSInteger a = 5;
NSNumber number = #(a); // ou #5;
to perform mathematical operations on 2 NSNumbers, you have to convert them to integer (or double, float...) before
NSNumber * number1 = #1;
NSNumber * number2 = #6;
NSInteger sum = [number1 integerValue] + [number2 integerValue];
for the fib problem, youre loop is correct. The way I would think of this is : I add my value in the for loop, and if I'm adding the 1st or 2nd element, then I put a 0, else I sum the last 2 elements:
- (NSArray *) fibbonacciSequenceWithSize:(NSInteger)size
{
NSMutableArray * result = [NSMutableArray new];
for(NSInteger idx = 0; i < size ; i ++)
{
// first 2 numbers of fib sequence are 1
if(idx == 0 || idx == 1)
{
[result addObject:#1];
}
else
{
// Add the 2 previous number
// F2 = F1 + F0
NSinteger next = [result[idx - 2] integerValue] + [result[idx - 1] integerValue];
[result addObject:#(next)];
}
}
return [result copy]; // copy the NSMutableArray in a NSArray
}
You can clean up the code by having a Fibonacci function that provides the sum of the last two elements.
- (NSNumber *)nextFibInArray:(NSArray *)array {
if (array.count < 2) return #1;
NSInteger lastIndex = array.count - 1;
return #([array[lastIndex-1] intValue] + [array[lastIndex] intValue]);
}
Then the loop is cleaner, too.
- (NSArray *)fibonacciWithLength:(NSInteger)length {
NSMutableArray *result = [#[] mutableCopy];
for (NSInteger i=0; i<length; i++) {
[result addObject:[self nextFibInArray:result]];
}
return result;
}
We could trim some execution time fat from this, but for short enough sequences, this should be clear and quick enough.

Copy specific index value of array to another array?

I am trying to copy a specific values at specific index from one array to another like this:
for (int i = 0; i < 100; i++) {
if ([subID[i] isEqual: #"0"]) {
NSLog(#"state : %#",arrayTempState[i]);
NSString *str = arrayTempState[i];
[arrayState addObject:str];
NSLog(#"%#",arrayState[i]);
}
arrayState is NSMutableArray and arrayTempState is NSArray
but arrayState is null every time.
I tried arrayState[i] = arrayTempState[i]; but it did not work.
arrayState was not initialised that is why it couldn't store the value.
plz try this
arrayState = [NSMutableArray array];
for (int i = 0; i < 100; i++) {
if ([subID[i] isEqual: #"0"]) {
NSLog(#"state : %#",arrayTempState[i]);
NSString *str = arrayTempState[i];
[arrayState addObject:str];
NSLog(#"%#",arrayState[i]);
}

NSMutableArray with int values from 1 to 100

This should be dead easy, but somehow it doesn't want to work for me. Using iOS 7 and XCode 5.
All I'm trying to do is create an array with values from 1 to 100.
NSMutableArray *array;
for (int i = 0; i < 100; i++)
{
[array addObject:i];
}
This doesn't work. I get a "Implicit conversion of 'int' to 'id' is disallowed with ARC.
I get it, I can't add primitive types to an NSMutableArray.
[array addObject:#i];
This doesn't work either. I get a "unexpected '#' in program"
[array addObject:[NSNumber numberWithInt:i]];
[array addObject:[NSNumber numberWithInteger:i]];
(either case) This "works" (compiles) but it really doesn't "work". The problem with this is that the value from NSNumber is really not a 1-100. What I get for each row is "147212864", 147212832", "147212840"...not what I want.
Lastly:
for (NSNumber *i = 0; i < [NSNumber numberWithInteger:100]; i++)
{
[array addObject:i];
}
This also doesn't compile. I get an error on the i++. "Arithmetic on pointer to interface 'NSNumber', which is not a constant size for this architecture and platform"
Any suggestions on how to do this extremely simple thing on obj-c?
Either one of these should work:
NSMutableArray *array = [NSMutableArray array];
for (int i = 0; i < 100; i++) {
[array addObject:#(i)];
}
or
NSMutableArray *array = [NSMutableArray array];
for (int i = 0; i < 100; i++) {
[array addObject:[NSNumber numberWithInt:i]];
}
Here are the reasons why your code snippets did not work:
[array addObject:i] - You cannot add primitives to Cocoa collections
[array addObject:#i] - You forgot to enclose the expression i in parentheses
NSNumber *i = 0; i < [NSNumber numberWithInteger:100]; i++ - You cannot increment NSNumber without "unwrapping" its value first.
If memory serves, I think you're simply missing parenthesis around the NSNumber shorthand expression.
NSMutableArray *array = [[NSMutableArray alloc] init];
for (NSUInteger i = 0; i < 100; i++)
{
[array addObject:#(i)];
}
Minimally, #i should be #(i) as described here. You are also forgetting to allocate and initialise your array
NSMutableArray *array = [[NSMutableArray alloc] init];
for (int i = 0; i < 100; i++) {
[array addObject:#(i)];
}
And since you are getting: "147212864", 147212832", "147212840"...not what I want., I think you are probably printing out your information wrongly or because the array is unallocated, that's simply garbage. Can you show us how you are outputting?
NSMutableArray *array = [[NSMutableArray alloc] init];
NSNumber *myNum;
for (int i = 0; i < 100; i++) {
myNum = [[NSNumber alloc]initWithInt:i];
[array addObject:myNum];
}
NSLog(#"%#", array); // 1 - 99 as expected
Worked for me :)
Just saying: Turn on all reasonable warnings in your Xcode project. Then read what the warnings are saying and do something about them. When you write something like
for (NSNumber *i = 0; i < [NSNumber numberWithInteger:100]; i++)
What does a for loop do? An object is in the end a pointer. So you initalise i to nil. Then you compare a pointer with a random pointer: [NSNumber numberWithInteger:100] returns a pointer to an object which could be anywhere in memory, and you compare pointers. Next the i++: No, you can't increment a pointer to an NSNumber. It doesn't make sense.

How does NSMutableArray achieve such high speed in fast enumeration

The y axis represents the the average access time (in ns) to each node in the list/array (total time to access all elements divided by the number of elements).
The x axis represents the number of elements in the array being iterated over.
Where red is an implementation of NSMutableArray and blue is my linked list (CHTape).
In each outer loop each list/array has a empty string #"" appended to it. In the inner loops each string in each list/array is retrieved, this is timed and recorded. After everything the times our outputted in a Wolfram Language output to produce a plot.
How does NSMutableArray achieve such amazing and consistent results? How can one achieve similar?
My NSFastEnumeration Implementation:
- (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(id __unsafe_unretained [])stackBuffer count:(NSUInteger)len
{
if (state->state == 0)
{
state->state = 1;
state->mutationsPtr = &state->extra[1];
state->extra[0] = (unsigned long)head;
}
CHTapeNode *cursor = (__bridge CHTapeNode *)((void *)state->extra[0]);
NSUInteger i = 0;
while ( cursor != nil && i < len )
{
stackBuffer[i] = cursor->payload;
cursor = cursor->next;
i++;
}
state->extra[0] = (unsigned long)cursor;
state->itemsPtr = stackBuffer;
return i;
}
Complete Testing Code:
NSMutableArray *array = [NSMutableArray array];
CHTape *tape = [CHTape tape];
unsigned long long start;
unsigned long long tapeDur;
unsigned long long arrayDur;
NSMutableString * tapeResult = [NSMutableString stringWithString:#"{"];
NSMutableString * arrayResult = [NSMutableString stringWithString:#"{"];
NSString *string;
int iterations = 10000;
for (int i = 0; i <= iterations; i++)
{
[tape appendObject:#""];
[array addObject:#""];
// CHTape
start = mach_absolute_time();
for (string in tape){}
tapeDur = mach_absolute_time() - start;
// NSArray
start = mach_absolute_time();
for (string in array){}
arrayDur = mach_absolute_time() - start;
// Results
[tapeResult appendFormat:#"{%d, %lld}", i, (tapeDur/[tape count])];
[arrayResult appendFormat:#"{%d, %lld}", i, (arrayDur/[array count])];
if ( i != iterations)
{
[tapeResult appendString:#","];
[arrayResult appendString:#","];
}
}
[tapeResult appendString:#"}"];
[arrayResult appendString:#"}"];
NSString *plot = [NSString stringWithFormat:#"ListPlot[{%#, %#}]", tapeResult, arrayResult];
NSLog(#"%#", plot);
By forcing ARC off on the link list related files efficiency increased dramatically. It reduced access time from ~70ns to ~14ns. While this is still slower, on average, then NSArray its only, on average, about two times slower, as opposed to ten times slower.
While ARC can make some code faster, in iterative situations adds unnecessary release/retain calls.
Discovered thanks to Greg Parker's comment.

Insert an object into NSMutable array and shift element one position ahead iOS

I want to insert an object (say 1.5) into NSMutableArray (say array with content: 1,2,3,4) between 1 and 2. The resultant array would be one element greater (say 1,1.5,2,3,4).
How can this be acheived in iOS using NSMutableArray?
Assuming you know the index to insert at, just use NSMutableArray's insertObject:atIndex: (reference). In your case, you want:
[yourMutableArray insertObject:#(1.5) atIndex:1];
If you don't know the index, you can do something like this (copy-pasted because nobody likes broken links):
#implementation NSMutableArray (SelfSorting)
- (void)insertNumberAtSortedLocation:(NSNumber *)aNumber
{
NSUInteger count = [self count];
// if there are no contents yet, simply add it
if (!count)
{
[self addObject:aNumber];
return;
}
NSRange searchRange;
searchRange.location = 0;
searchRange.length = count;
// bubble sort finding of insert point
do
{
NSInteger index = searchRange.location + searchRange.length/2;
NSNumber *testNumber = [self objectAtIndex:index];
switch ([aNumber compare:testNumber])
{
case NSOrderedAscending:
{
//searchRange.length = searchRange.length / 2;
searchRange.length = index - searchRange.location;
break;
}
case NSOrderedDescending:
{
int oldLocation = searchRange.location;
searchRange.location = index+1;
searchRange.length = searchRange.length - (searchRange.location - oldLocation);
break;
}
case NSOrderedSame:
{
searchRange.length = 0;
searchRange.location = index;
break;
}
}
} while (searchRange.length>0);
// insert at found point
[self insertObject:aNumber atIndex:searchRange.location];
}
And then, call:
[yourMutableArray insertNumberAtSortedLocation:#(1.5)];
Two lines of code
Just append the item and then sort or sort at usage time, sorting is actually very cheap, almost O(n) for non pathological cases.
NSMutableArray *a = [#[#1, #2 ,#3 ,#4] mutableCopy];
// Two lines of code:
[a addObject:#(1.5)];
[a sortUsingSelector:#selector(compare:)];
NSLog(#"a: %#", a);
NSLog oputput:
a: (
1,
"1.5",
2,
3,
4
)
The above should be O(log n)
Or if you don't want the entire array sorted, just insert after the first entry that is less than it:
NSUInteger count = [a count];
int index = 0;
while (index < count && [a[index] compare:aNumber] == NSOrderedAscending) {
index += 1;
}
[a insertObject:aNumber atIndex:index];
The above is O(n) as opposed to a binary search which is O(log n) but for most arrays there is not a meaningful time difference.
For the example in your question, you would write [array insertObject:#(1.5) atIndex:1]
NSMutableArray * foo = [[NSMutableArray alloc] init];
[foo insertObject:<#(id)#> atIndex:<#(NSUInteger)#>]

Resources