I have such method and have a hard time optimizing it to run better. It takes roughly 1 sec with 100 units and 4 times to get between NSLog(@"Debug2") and NSLog(@"Debug3"). And 2 sec on iPhone. With more units it takes more. 250 units and 5 times it takes 1,7 sec on mac, and 3,2 sec on iphone.
I don’t think the performance lies in cycle within a cycle. As 250 * 5 = 1250, should not be too much for a computer to handle fast.
Method idea:
Input: NSMutableArray times – containing times (2012-12-12, 2013-01-19) and etc
NSMutableArray objectArray – contains LogUnit objects.
Output: Array of computed views.
Main idea: a view for each time with objects from ObjectArray whose time is the same.
I have made it faster by showing a small proportion of objects (see counted in code and _breakPlease), yet it’s still not fast enough.
- (NSMutableArray*) sortViews: (NSMutableArray *)times and:(NSMutableArray *)objectArray
{
NSLog(@"debug2");
NSMutableArray *views = [[NSMutableArray alloc] initWithCapacity:times.count];
NSString *number = [NSString stringWithFormat:@"SortLog%i ",[[NSUserDefaults standardUserDefaults] stringForKey:@"ObjectNumber"].intValue];
NSString *comp = [[NSUserDefaults standardUserDefaults] stringForKey:number];
LogUnit *unit;
int counted = 0;
for(int x = 0; x != times.count; x++)
{
@autoreleasepool {
UIView *foo = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 400)];
foo.backgroundColor = [UIColor clearColor];
int f = 0;
int h = 0;
NSString *attributeName = @"realTime";
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"%K IN %@", attributeName, [times objectAtIndex:x]];
// Filter the objectArray by the time, so we don't have to run through all the objects in objectArray, and check if time is right.
NSArray *filtered = [objectArray filteredArrayUsingPredicate:predicate];
for(int i = 0; i != filtered.count; i++)
{
unit = [filtered objectAtIndex:i];
// Filter units by user choice (comp). Like comp = Warnings or comp = Errors and etc.
if([[unit status] isEqualToString:comp] || [comp isEqualToString:NULL] || comp == NULL)
{
// testing if the unit is correct to use
if([unit getEvent] != NULL)
{
// below is some computation for frames, to get them to proper position
unit.view.frame = CGRectMake(unit.view.frame.origin.x, f * unit.view.frame.size.height + 30, unit.view.frame.size.width, unit.view.frame.size.height);
[foo addSubview:unit.view];
counted++;
f++;
h = unit.view.frame.size.height * f;
}
}
}
UILabel *myLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 320, 30)];
myLabel.backgroundColor = [UIColor clearColor];
myLabel.font = [UIFont boldSystemFontOfSize:20];
myLabel.textColor = [UIColor colorWithRed:88 green:154 blue:251 alpha:1];
myLabel.textAlignment = UITextAlignmentCenter;
myLabel.text = [times objectAtIndex:x];
// Just adding a label with "2012-12-30" or etc on top of the view.
[foo addSubview:myLabel];
foo.frame = CGRectMake(0,0, 320, h + 30 );
h = 0;
[views addObject:foo];
// counting added views for performance, if more than 30, return, and show only small portion of whole units, user has the option to show all the units if he wants to, but that takes a time to load..
if(counted > 30 && filtered.count != counted)
{
if(_breakPlease == false)
{
_broken = true;
break;
}
}
}
}
NSLog(@"debug3");
return views;
}
Several things for you to try.
First for profiling:
Now for optimization:
UIViewand archive it and unarchive it whenever you need a new view. Apply this also to theUILabel;NSPredicateand apply some values later. This way you can reuse the sameUIPredicate;UIColoras we don’t know howUIColorhandles it;forloop i.e. you have a maximum number of correct units ?Well, the profiler should be enough for you to understand where is your bottleneck but I’ve let you with some ideas also.
Don’t forget to report here the results! 🙂