iPad App运行缓慢,经过一段时间的崩溃

时间:2014-08-05 12:02:49

标签: ios iphone ipad profiling instruments

在按钮上点击大约60多次我的iPad应用程序变慢然后最终崩溃

开始我的应用程序正常工作,经过一段时间它变得缓慢而且更慢......

响应动作大约需要8到10秒,最后崩溃  我不知道为什么这一切都在发生。  我在uiviewcontroller上使用了collectionview,它的所有内容视图都是在custome cell class中创建的。

使用乐器在iPAd 2上进行测试后,

进行了这些屏幕拍摄。

现在该怎么办?你有没有看到任何问题... ???

这里是UICollectionView Cell中的加号按钮执行操作,按钮点按时间随机增加,达到300000+ ms

注意--->主线程显示0.0 ms

这是什么意思...... ????

请指导我正确的方向

enter image description here

enter image description here

enter image description here

修改

这是我在按钮上点击这些方法的代码

 // 'purchasedProduct' is NSMutuableDictionary    

-(void)btnPlus:(id)sender event:(id)event
{
    indexPaths   = [[NSMutableArray alloc]init];        
    NSSet *touches = [event allTouches];
    UITouch *touch = [touches anyObject];
    CGPoint currentTouchPosition = [touch locationInView:myCollection];
    btnIndex = [myCollection indexPathForItemAtPoint: currentTouchPosition];
    MyCell *cell = (MyCell*)[myCollection cellForItemAtIndexPath:btnIndex];
    NSString *newCode = [productID objectAtIndex:btnIndex.row];
    newQty = cell.cellQty.text;
    newQty = [NSString stringWithFormat:@"%d",[newQty integerValue] + 1];
    BOOL currentCellHasUpdates = purchasedProduct[newCode] != nil;
    if (currentCellHasUpdates)
    {
        // Object Already Exist.......
        [purchasedProduct setObject:newQty  forKey:newCode];
        prdID = newCode;
        [self UpdateProduct];
    }
    else
    {
        // create new object........
        [purchasedProduct setObject:newQty  forKey:newCode];
        prdID = newCode;
        [self BuyProduct];
    }
    [indexPaths addObject:btnIndex];
    [myCollection reloadItemsAtIndexPaths:indexPaths]; // I think problem is here.
}

CellForItemAtIndexPath方法是

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
MyCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"CellID" forIndexPath:indexPath];
[[cell cellBtnPlus] addTarget:self action:@selector( btnPlus:event:) forControlEvents:UIControlEventTouchUpInside];

[[cell cellBtnMinus] addTarget:self action:@selector(btnMinus:event:) forControlEvents:UIControlEventTouchUpInside];

BOOL currentCellHasUpdates = purchasedProduct[[productID objectAtIndex:indexPath.row]] != nil;
if (currentCellHasUpdates)
{
    cell.cellQty.text = [purchasedProduct objectForKey: [productID objectAtIndex:indexPath.row]];
    cell.cellQty.textColor = [UIColor blueColor];
}
else
{
    cell.cellQty.textColor = [UIColor lightGrayColor];
    cell.cellQty.text = @"0";
}

image = nil;    
NSString *imageName =[[productID objectAtIndex:indexPath.row] stringByAppendingString:@".jpg"];
getImagePath = [documentsDirectory stringByAppendingPathComponent:imageName];
image = [UIImage imageWithData:[NSData dataWithContentsOfFile:getImagePath]];

if (image.size.width == image.size.height)
{
    //set newSize
}
if (image.size.width < image.size.height)
{
    //calculate newSize
}
else
{
    //calculate newSize
}

UIGraphicsBeginImageContext( newSize );
[image drawInRect:CGRectMake(0,0,newSize.width,newSize.height)];
image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
if (image.size.width == image.size.height)
{
    //set imgRect
}
if (image.size.width < image.size.height)
{
    //Calculations for imgRect
}
if (image.size.width > image.size.height)
{
    //Calculations for imgRect
}
cell.myImageView.frame = imgRect;
cell.myImageView.image = image;

cell.lbl1.text = [[desc objectAtIndex:indexPath.row]  capitalizedString];
cell.lbl2.text = [@"Box Qty:" stringByAppendingString:[boxQty objectAtIndex:indexPath.row]];
cell.lbl4.text = [[code objectAtIndex:indexPath.row] uppercaseString];
cell.lbl5.text = [@"Pack Qty:" stringByAppendingString:[packQty objectAtIndex:indexPath.row]];

BOOL isStarProduct = starProducts[[productID objectAtIndex:indexPath.row]] != nil;
if (isStarProduct)
{
    cell.lbl6.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:@"star.png"]];
}
else
{
    cell.lbl6.backgroundColor = [UIColor clearColor];
}

return cell;
}

我认为问题是在CollectionView 中的特定索引路径上重新加载导致问题,因为它需要91%的时间来执行。我是对的.. ???

编辑2

-(void)BuyProduct
{
newDate = [NSDate date];
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
currentDate = [formatter stringFromDate:newDate];

database = [dBName UTF8String];
if (sqlite3_open(database, &dbConnection) == SQLITE_OK)
{
    sqliteQuery = [NSString stringWithFormat:@"INSERT INTO ShopingCart"
                   " (fld1 , fld2, fld3, fld4, fld5, fld6, fld7, fld8, fld9, fld10, fld11, fld12, fld13, fld14, fld15, fld16)"
                   " VALUES (\'%d\', \"%@\", \'%d\', \"%@\", \"%@\", \"%@\", \"%f\", \"%f\", \"%@\", \"%@\","
                   " \"%@\", \"%f\", \"%.4f\", \'%d\', \'%d\', \'%d\')",
                   1,
                   currentDate,
                   91,
                   customerID,
                   [productID objectAtIndex:btnIndex.row],
                   [costPrice objectAtIndex:btnIndex.row],
                   [[price objectAtIndex:btnIndex.row] floatValue] * [newQty integerValue],
                   [[salePrice objectAtIndex:btnIndex.row] floatValue] * [newQty integerValue],
                   [qty objectAtIndex:btnIndex.row],
                   newQty,
                   [taxRate objectAtIndex:btnIndex.row],
                   [[price objectAtIndex:btnIndex.row] floatValue] * [newQty integerValue],
                   [[price objectAtIndex:btnIndex.row] floatValue] * [newQty integerValue] + [taxAmount floatValue],
                   0,
                   0,
                   0];
    if (sqlite3_prepare_v2(dbConnection, [sqliteQuery UTF8String], -1, &sQLStatement, NULL) == SQLITE_OK)
    {
        if (sqlite3_step(sQLStatement) == SQLITE_DONE)
        {
            NSLog(@"Inserted into Shopping Cart");
        }
        sqlite3_finalize(sQLStatement);
    }

    sqliteQuery = [NSString stringWithFormat:@"SELECT SUM(NetPrice) As TotalAmount"
                   " FROM ShopingCart WHERE CustomerID = \'%@\'",customerID];
    if (sqlite3_prepare_v2(dbConnection, [sqliteQuery UTF8String], -1, &sQLStatement, NULL) == SQLITE_OK)
    {
        if (sqlite3_step(sQLStatement) == SQLITE_ROW)
        {
            temp = [[NSString alloc] initWithUTF8String:(const char *) sqlite3_column_text(sQLStatement, 0)];
        }
        sqlite3_finalize(sQLStatement);
    }
    ordAmount.text = [NSString stringWithFormat:@"Total £ %.2f",[temp floatValue]];
}
else
{
    NSLog(@"Error %s ", sqlite3_errmsg(dbConnection));
}
sqlite3_close(dbConnection);
}

我应该/我可以在哪里改进我的代码?

1 个答案:

答案 0 :(得分:3)

你的文书清楚地表明reloadItemsAtIndexPaths:是经验不佳表现的罪魁祸首。这意味着集合视图需要很长时间才能使单元格出列。

看看你的cellForRowAtIndexPath:方法,你的for循环似乎是一个有吸引力的赌注,因为你的表现会受到影响。对于每个单元格,您要迭代一系列希望满足以下条件的产品

if ([[productID objectAtIndex:indexPath.row] isEqualToString:[updatedCodes objectAtIndex:i]])
{
    cell.cellQty.text = [updatedQty objectAtIndex:i];
    cell.cellQty.textColor = [UIColor blueColor];
}

一旦这个条件成立,你就更新了单元格,但是你没有摆脱循环!

这意味着对于您遍历整个数组的每个单元格!你应该做的是在if中放置一个break语句来打破循环。

话虽如此,我认为我们可以变得更好。鉴于您有一个productID数组和一个updatedCodes数组,您真的应该考虑将这些与Dictionary相匹配。字典是通过特定键获取对象的好方法。可以将数组视为字典,其中键是数组索引。因此,当您在索引0处获取对象时,实际上是在获取其键为0的对象。因此,在您的示例中,productID自然可以是您的键,值将是产品。如果您知道相应的productID,这将允许您立即获取任何产品。

因此,您需要一本包含所有产品的字典。然后,您将需要一个包含所有更新代码的字典。您可以让集合视图显示字典中的所有产品(NSDictionary具有方法&#34; allValues&#34;)或者您可以拥有一系列产品。

所以你需要的基本想法是:

  1. 要在集合视图中显示的所有产品的数组(让我们称之为productsArray)。
  2. 按产品ID键入的产品词典 - NSDictionary *productsKeyedByID = [NSDictionary dictionaryWitObjects:productsArray forKeys:[productsArray valueForKey:@"productID"]];\\where productID is a property on the product object
  3. 更新产品词典。当项目更新时,这将被修改。
  4. 此方法背后的动机是允许您根据特定的产品ID快速访问产品或更新的产品。这意味着对于阵列中的每个产品,您都可以立即检查它是否存在于更新的产品词典中。

    所以在你的cellForRowAtIndexPath中:你可以拥有

    MyCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"CellID" forIndexPath:indexPath];
    [[cell cellBtnPlus] addTarget:self action:@selector( btnPlus:event:) forControlEvents:UIControlEventTouchUpInside];
    
    [[cell cellBtnMinus] addTarget:self action:@selector(btnMinus:event:) forControlEvents:UIControlEventTouchUpInside];
    
    NSString *currentCellProductId = productsArray[indexPath.row];
    //using the modern syntax - you could also use the objectForKey: method.
    BOOL currentCellHasUpdates = updatedCodesKeyedByID[currentCellProductId] != nil;
    if (currentCellHasUpdates) {
        cell.cellQty.text = updatedCodesKeyedByID[currentCellProductId].quantity;
        cell.cellQty.textColor = [UIColor blueColor];
    } else {
        cell.cellQty.textColor = [UIColor lightGrayColor];
        cell.cellQty.text = @"0";
    }
    

    现在,在处理按钮时,您还可以利用词典的强大功能:

    -(void)btnPlus:(id)sender event:(id)event
    {
        NSSet *touches = [event allTouches];
        UITouch *touch = [touches anyObject];
        CGPoint currentTouchPosition = [touch locationInView:myCollection];
        btnIndex = [myCollection indexPathForItemAtPoint: currentTouchPosition];
        MyCell *cell = (MyCell*)[myCollection cellForItemAtIndexPath:btnIndex];
        NSString *newCode = [productID objectAtIndex:btnIndex.row];
        newQty = cell.cellQty.text;
        if (updatedCodesKeyedByID[newCode] != nil)
        {
            //NSLog(@"Object Already Exist...");
             id codeToUpdate = updatedCodesKeyedByID[newCode];
             codeToUpdate.quantity++;
             [self UpdateProduct]; // Open DB SQlite DB Connection and update Table Record and Close Connection.
          } 
          else
          {
               updatedCodesKeyedByID[newCode] = //create new object
               [self BuyProduct]; // Open DB SQlite DB Connection and update Table Record and Close Connection.
          }
     } 
    

    注意您可能需要考虑将设计更改为只有一个包含产品的词典,并且每个产品都有关联的数量。未设置时,默认为0。这样你只需要检查一个词典就可以完成你在这篇文章中所做的事情。即更新项目的数量。

    在将此讨论转移到聊天之后,

    编辑,最后一个难题是调用UICollectionView的reloadItemsAtIndexPaths:在performBatchUpdates块中。