如何在iPhone上使用内省+重分配来优化代码

时间:2022-09-06 13:39:27

I have a problem. I try to display a UITable that could have 2000-20000 records (typicall numbers.)

我有个问题。我尝试显示一个可能有2000-20000条记录的UITable(典型数字。)

I have a SQLite database similar to the Apple contacts application.

我有一个类似于Apple联系人应用程序的SQLite数据库。

I do all the tricks I know to get a smoth scroll, but I have a problem.

我做了我知道的所有技巧以得到一个smoth卷轴,但我有一个问题。

I load the data in 50 recods blocks. Then, when the user scroll, request next 50 until finish the list.

我将数据加载到50个recods块中。然后,当用户滚动时,请求下一个50直到完成列表。

However, load that 50 records cause a notable "pause" in loading and scrolling. Everything else works fine.

但是,加载50条记录会导致加载和滚动时出现明显的“暂停”。其他一切都很好。

I cache the data, have opaque cells, draw it by code, etc...

我缓存数据,有不透明的单元格,通过代码绘制等等...

I swap the code loading the same data in dicts and have a performance boost but wonder if I could keep my object oriented aproach and improve the actual code.

我交换了代码中加载相同数据的代码,并提高了性能但是想知道我是否可以保持面向对象的方法并改进实际的代码。

This is the code I think have the performance problem:

这是我认为有性能问题的代码:

    -(NSArray *) loadAndFill: (NSString *)sql theClass: (Class)cls {
        [self openDb];

        NSMutableArray *list = [NSMutableArray array];

        NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

        DbObject *ds;
        Class myClass = NSClassFromString([DbObject getTableName:cls]);

        FMResultSet *rs = [self load:sql];

        while ([rs next]) {
            ds = [[myClass alloc] init];
            NSDictionary *props = [ds properties];
            NSString *fieldType = nil;
            id fieldValue;

            for (NSString *fieldName in [props allKeys]) {
                fieldType = [props objectForKey: fieldName];

                fieldValue = [self ValueForField:rs Name:fieldName Type:fieldType];

                [ds setValue:fieldValue forKey:fieldName];
            }

            [list addObject :ds];

            [ds release];
        }
        [rs close];

        [pool drain];
        return list;
    }

And I think the main culprit is:

我认为主要的罪魁祸首是:

    -(id) ValueForField: (FMResultSet *)rs Name:(NSString *)fieldName Type:(NSString *)fieldType {
        id fieldValue = nil;

        if ([fieldType isEqualToString:@"i"] || // int
                 [fieldType isEqualToString:@"I"] || // unsigned int
                 [fieldType isEqualToString:@"s"] || // short
                 [fieldType isEqualToString:@"S"] || // unsigned short
                 [fieldType isEqualToString:@"f"] || // float
                 [fieldType isEqualToString:@"d"] )  // double
        {
            fieldValue = [NSNumber numberWithInt: [rs longForColumn:fieldName]];
        }
        else if ([fieldType isEqualToString:@"B"]) // bool or _Bool
        {
            fieldValue = [NSNumber numberWithBool: [rs boolForColumn:fieldName]];
        }
        else if ([fieldType isEqualToString:@"l"] || // long
                 [fieldType isEqualToString:@"L"] || // usigned long
                 [fieldType isEqualToString:@"q"] || // long long
                 [fieldType isEqualToString:@"Q"] ) // unsigned long long
        {
            fieldValue = [NSNumber numberWithLong: [rs longForColumn:fieldName]];
        }
        else if ([fieldType isEqualToString:@"c"] || // char
                 [fieldType isEqualToString:@"C"] ) // unsigned char

        {
            fieldValue = [rs stringForColumn:fieldName];
            //Is really a boolean?
            if ([fieldValue isEqualToString:@"0"] || [fieldValue isEqualToString:@"1"]) {
                fieldValue = [NSNumber numberWithInt: [fieldValue intValue]];
            }
        }
        else if ([fieldType hasPrefix:@"@"] ) // Object
        {
            NSString *className = [fieldType substringWithRange:NSMakeRange(2, [fieldType length]-3)];

            if ([className isEqualToString:@"NSString"]) {
                fieldValue = [rs stringForColumn:fieldName];
            }
            else if ([className isEqualToString:@"NSDate"]) {
                NSDateFormatter* dateFormatter = [[NSDateFormatter alloc] init];
                [dateFormatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ss"];
                NSString *theDate = [rs stringForColumn:fieldName];

                if (theDate) {
                    fieldValue = [dateFormatter dateFromString: theDate];
                }
                else
                {
                    fieldValue = nil;
                }

                [dateFormatter release];
            }
            else if ([className isEqualToString:@"NSInteger"]) {
                fieldValue = [NSNumber numberWithInt: [rs intForColumn :fieldName]];
            }
            else if ([className isEqualToString:@"NSDecimalNumber"]) {
                fieldValue = [rs stringForColumn :fieldName];
                if (fieldValue) {
                    fieldValue = [NSDecimalNumber decimalNumberWithString:[rs stringForColumn :fieldName]];
                }
            }
            else if ([className isEqualToString:@"NSNumber"]) {
                fieldValue = [NSNumber numberWithDouble: [rs doubleForColumn:fieldName]];
            }
            else
            {
                //Is a relationship one-to-one?
                if (![fieldType hasPrefix:@"NS"]) {
                    id rel =  class_createInstance(NSClassFromString(className), sizeof(unsigned));
                    Class theClass = [rel class];
                    if ([rel isKindOfClass:[DbObject class]]) {
                        fieldValue = [rel init];
                        //Load the record...
                        NSInteger Id = [rs intForColumn:[theClass relationName]];
                        if (Id>0) {
                            [fieldValue release];

                            Db *db = [Db currentDb];

                            fieldValue = [db loadById: theClass theId:Id];
                        }
                    }
                } else {

                    NSString *error = [NSString stringWithFormat:@"Err Can't get value for field %@ of type %@", fieldName, fieldType];

                    NSLog(error);
                    NSException *e = [NSException
                                      exceptionWithName:@"DBError"
                                      reason:error
                                      userInfo:nil];
                    @throw e;
                }
            }
        }
        return fieldValue;
    }

2 个解决方案

#1


You should be able to run this program with "Instruments" using the sampler tool to figure out where the problem is. You can rewrite ValueForField into smaller calls to see which part of it is the bottleneck, if necc.

您应该能够使用“仪器”使用“仪器”运行该程序,以找出问题所在。您可以将ValueForField重写为较小的调用,以查看它的哪个部分是瓶颈,如果是necc。

Other possibilities: If the data is static, you could load much (all of it?) at once into C arrays (especially for the ints and bools). If there are lots of values that are the same, you can share objects for the alike ones - eg: if the table has 20,000 lines, and 18,000 have the same string for some column, you can just make one string and share it.

其他可能性:如果数据是静态的,你可以将多个(全部?)加载到C数组中(特别是对于int和bools)。如果有许多相同的值,您可以共享相同的对象 - 例如:如果表有20,000行,并且18,000对于某些列具有相同的字符串,则可以只创建一个字符串并共享它。

#2


Look like the performance problem is with decimalNumberWithString.

看起来性能问题是使用decimalNumberWithString。

If I remove that from the code, the delay is a lot smaller than with it.

如果我从代码中删除它,延迟比它小很多。

Is bad that I need NSDecimalNumber for currency managment :(

是不是我需要NSDecimalNumber进行货币管理:(

#1


You should be able to run this program with "Instruments" using the sampler tool to figure out where the problem is. You can rewrite ValueForField into smaller calls to see which part of it is the bottleneck, if necc.

您应该能够使用“仪器”使用“仪器”运行该程序,以找出问题所在。您可以将ValueForField重写为较小的调用,以查看它的哪个部分是瓶颈,如果是necc。

Other possibilities: If the data is static, you could load much (all of it?) at once into C arrays (especially for the ints and bools). If there are lots of values that are the same, you can share objects for the alike ones - eg: if the table has 20,000 lines, and 18,000 have the same string for some column, you can just make one string and share it.

其他可能性:如果数据是静态的,你可以将多个(全部?)加载到C数组中(特别是对于int和bools)。如果有许多相同的值,您可以共享相同的对象 - 例如:如果表有20,000行,并且18,000对于某些列具有相同的字符串,则可以只创建一个字符串并共享它。

#2


Look like the performance problem is with decimalNumberWithString.

看起来性能问题是使用decimalNumberWithString。

If I remove that from the code, the delay is a lot smaller than with it.

如果我从代码中删除它,延迟比它小很多。

Is bad that I need NSDecimalNumber for currency managment :(

是不是我需要NSDecimalNumber进行货币管理:(