2016-03-31 13 views
2

Ich muss die Leistung einer mit Parse verbundenen iOS-App verbessern. Bisher habe ich überprüft, dass einige findObject-Abfragen zu lange dauern, einige sogar 10 Sekunden!Abfragen analysieren, die zu lange dauern

Ich werde den Code von einer der schlimmsten Fälle setzen und was ich bisher versucht:

+ (void) getAllEvents 
{ 
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 

    PFQuery *timestampsQuery = [PFQuery queryWithClassName:@"TimeStamp"]; 
    [timestampsQuery fromLocalDatastore]; 
    [timestampsQuery whereKey:@"type" equalTo:@"event"]; 
    // This query very often (not always) takes a couple of seconds 
    NSArray *timeStampObjects = [timestampsQuery findObjects]; 
    NSArray *timeStamps = [self TransformPFObjectIntoTimeStamp:timeStampObjects]; 

    PFQuery *query = [PFQuery queryWithClassName:@"Event"]; 
    if ([self noNetworkConnection]) 
    { 
     [query fromLocalDatastore]; 
    } 
    else 
    { 
     [query whereKey:@"user" equalTo:[PFUser currentUser]]; 
    } 
    [query includeKey:@"admin"]; 
    // This query very often (not always) takes several seconds, 6, 7…even 10 seconds! 
    NSArray *objects = [query findObjects];   
    NSMutableArray *eventArray = [NSMutableArray arrayWithArray:[self TransformPFObjectIntoEvents:objects]]; 

    NSDictionary* dict = [NSDictionary dictionaryWithObjectsAndKeys:eventArray,@"events",timeStamps,@"timestamps", nil]; 
    dispatch_async(dispatch_get_main_queue(), ^{ 
     [[NSNotificationCenter defaultCenter] postNotificationName:GET_ALL_MY_EVENTS object:dict]; 
    }); 

    }); 
} 

+ (NSArray *)TransformPFObjectIntoTimeStamp:(NSArray *)objects 
{ 
    NSMutableArray* timestamps = [[NSMutableArray alloc]init]; 
    for (PFObject* object in objects) 
    { 
     TimeStamp* timeStamp = [[TimeStamp alloc] init]; 
     timeStamp.parseObject = object; 
     [timestamps addObject:timeStamp]; 
    } 
    return timestamps; 
} 

+ (NSMutableArray *)TransformPFObjectIntoEvents:(NSArray *)objects 
{ 
    [PFObject pinAllInBackground:objects withName:PFObjectDefaultPin]; 
    NSMutableArray* eventArray = [[NSMutableArray alloc]init]; 
    for (PFObject* object in objects) 
    { 
     Event* event = [[Event alloc] init]; 
     event.parseObject = object; 
     PFInstallation *currentInstallation = [PFInstallation currentInstallation]; 
     [currentInstallation addUniqueObject:object[@"channel"] forKey:@"channels"]; 
     [currentInstallation saveInBackground]; 
     if(event.parseObject[@"imageFile"] != [NSNull null]) 
     { 
     PFFile *userImageFile = event.parseObject[@"imageFile"]; 
     if (userImageFile != NULL) 
     { 
      UIImage *image = [UIImage imageWithData:[userImageFile getData]]; 
      [event setAttributeImage:image]; 
     } 
     } 
     [eventArray addObject:event]; 
    } 
    return eventArray; 
} 

ich hinzufügen muss, dass der zweite Aufruf von findObjects manchmal gibt mir ein „CFNetwork gescheitert sslhandshake (-9824)“, die mir fremd ist, weil die App die info.plist mit diesen Tasten hat (aber ich denke, das in einer anderen Frage sein sollte):

<key>NSTemporaryExceptionRequiresForwardSecrecy</key> 
<false/> 
<key>NSAppTransportSecurity</key> 
<dict> 
    <key>NSAllowsArbitraryLoads</key> 
    <true/> 
</dict> 

Und eine andere Sache, Tabelle‚Ereignis‘hat über 1000 Register.

Was ich habe versucht:

1) Kommentar [timestampsQuery fromLocalDatastore]; Gleiche Ergebnisse, diese Abfragen dauern zu lange.

2) Benutzer findObjectInBackground:

+ (void) getAllMyEvents{ 
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 
    _calls = 0; 
    PFQuery *timestampsQuery = [PFQuery queryWithClassName:@"TimeStamp"]; 
    [timestampsQuery fromLocalDatastore]; 
    [timestampsQuery whereKey:@"type" equalTo:@"event"]; 
    [timestampsQuery findObjectsInBackgroundWithBlock:^(NSArray * _Nullable objects, NSError * _Nullable error) { 
     [self completeQueriesWithType:1 andObjects:objects]; 
    }]; 

    PFQuery *query = [PFQuery queryWithClassName:@"Event"]; 
    if ([self noNetworkConnection]) 
    { 
     [query fromLocalDatastore]; 
    } 
    else 
    { 
     [query whereKey:@"user" equalTo:[PFUser currentUser]]; 
    } 
    [query includeKey:@"admin"]; 
    [query findObjectsInBackgroundWithBlock:^(NSArray * _Nullable objects, NSError * _Nullable error) { 
     [self completeQueriesWithType:2 andObjects:objects]; 
    }] ; 
}); 
} 

+ (void) completeQueriesWithType:(int)type andObjects:(NSArray *)objs 
{ 
    _calls++; 
    NSArray *timeStamps = nil; 
    NSMutableArray *eventArray = nil; 
    if(type == 1) 
    { 
     timeStamps = [TimeStamp TransformPFObjectIntoTimeStamp:objs]; 
    } 
    else if(type == 2) 
    { 
     eventArray = [NSMutableArray arrayWithArray:[self TransformPFObjectIntoEvents:objs]]; 
    } 
    if(_calls == 2) 
    { 
     NSDictionary* dict = [NSDictionary dictionaryWithObjectsAndKeys:eventArray,@"events",timeStamps,@"timestamps", nil]; 
     dispatch_async(dispatch_get_main_queue(), ^{ 
      [[NSNotificationCenter defaultCenter] postNotificationName:GET_ALL_MY_EVENTS object:dict]; 
     }); 
    } 
} 

Aber es ist immer noch Sekunden dauern, und ich habe diesen Fehler bekommt auch: „Warnung: Eine lang andauernde Operation auf dem Haupt-Thread ausgeführt wird. break on warnBlockingOperationOnMainThread() zu debuggen. "Warum? Wenn ich das im Hintergrund laufen lasse.

Da ich weiß, Parse lokale Datenbank hat einige Auswirkungen auf die Leistung Ich habe zwar auf überhaupt nicht verwenden, entfernen Sie alle seine Erscheinungen, aber ich möchte das Problem mit Parse lokale Datenbank reparieren, wenn es möglich ist.

Also ... warum brauchen diese Abfragen so viel Zeit?

EDIT: Nach @Wain Vorschlag, den ich mit diesem Test beendet haben:

+ (void) getAllEvents 
{ 
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 
    NSLog(@"Running only second of findObjects"); 
    PFQuery *query = [PFQuery queryWithClassName:@"Event"]; 
    if ([self noNetworkConnection]) 
    { 
     NSLog(@"Reading from local datastore"); 
     [query fromLocalDatastore]; 
    } 
    else 
    { 
     [query whereKey:@"user" equalTo:[PFUser currentUser]]; 
    } 
    [query includeKey:@"admin"]; 
    // This query very often (not always) takes several seconds, 6, 7…even 10 seconds! 
    NSLog(@"Just before findObjects"); 
    NSArray *objects = [query findObjects];   
    NSLog(@"End of running only second of findObjects"); 
    }); 
} 

Mit diesen Ergebnissen:

2016-03-31 11:15:29.295 MyApp[...] Running only second of findObjects 
2016-03-31 11:15:29.318 MyApp[...] Just before findObjects 
2016-03-31 11:15:38.025 MyApp[...] End of running only second of findObjects 

Nur diese Methode NSArray * Objekte = [Abfrage findObjects] ; dauert 9 Sekunden!

EDIT 2 Ich bin mir nicht sicher, ob dies wichtig ist, aber eines der Felder in der „Event“ Tabelle ist eine PFFile (ein Bild). Könnte das die Suchabfrage verlangsamen?

Antwort

0

Es gibt eine Reihe von Dingen, die Sie ändern könnten, aber Sie sollten Instrumente verwenden, um zu sehen, was die meiste Zeit kostet.Dinge zu beachten:

  1. Sie die ersten Downloads nicht laufen seriell
  2. Rufen Sie nicht PFInstallation *currentInstallation = [PFInstallation currentInstallation]; & [currentInstallation saveInBackground]; innerhalb einer Schleife
  3. nicht jedes Bild seriell UIImage *image = [UIImage imageWithData:[userImageFile getData]];
in einer Schleife downloaden Sie

Sie betrachten den anfänglichen Download als den Schuldigen, aber es ist viel wahrscheinlicher, dass Sie Ihre nachfolgende Verarbeitung durchführen, bei der Sie eine Menge Installationsinstallationen und synchrone Bilddownloads starten ...

+0

Wenn Sie sagen "nicht die ersten Downloads seriell ausführen", meinen Sie, dass ich so etwas wie meinen 2. Test mit findObjectsInBackground tun und die Ergebnisse mischen sollte? – Wonton

+0

ja, aber das scheint nicht die Hauptursache für den Zeitaufwand zu sein, schauen Sie sich zuerst die Bilddownloads an ... – Wain

Verwandte Themen