2012-04-09 1 views
1

Ich verwende AFNetworking, um Bilder von einer URL zu ziehen, die Größe zu ändern, auf Festplatte zu speichern und den Pfad in Core Data zu protokollieren, dann in eine Tabellenansicht zu laden und zu speichern. Wenn der Code ausgeführt wird, friert er meine Benutzeroberfläche ein. Ich bin mir nicht sicher, ob der Download oder die Manipulation meine Probleme verursacht.AFNetworking für Image-Downloads, nicht reagierende Benutzeroberfläche

Der Code Ich verwende unter

- (void)getPhoto:(NSInteger)type forManagedObject:(MyManagedObject*)object { 

    // download the photo 
    NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:object.photoUrl]]; 
    AFImageRequestOperation *operation = [AFImageRequestOperation imageRequestOperationWithRequest:request success:^(UIImage *image) { 


     // MyManagedObject has a custom setters (setPhoto:,setThumb:) that save the 
     // images to disk and store the file path in the database 
     object.photo = image; 
     object.thumb = [image imageByScalingAndCroppingForSize:CGSizeMake(PhotoBlockCellButtonWidth, PhotoBlockCellButtonHeight)]; 

     NSError *nerror; 
     if (![[DataStore sharedDataStore].managedObjectContext save:&nerror]) { 
      NSLog(@"Whoops, couldn't save: %@", [nerror localizedDescription]); 
      return; 
     } 

     // notify the table view to reload the table 
     [[NSNotificationCenter defaultCenter] postNotificationName:@"ReloadTableView" object:nil]; 

    }]; 
    [operation start]; 
}

Und hier ist ein Beispielcode, die für die Setter von meinem verwalteten Objekt

- (NSString*)uniquePath{ 

    // prepare the directory string 
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); 
    NSString *documentsDirectory = [paths objectAtIndex:0]; 

    // acquire a list of all files within the directory and loop creating a unique file name 
    NSFileManager *fileManager = [NSFileManager defaultManager]; 
    NSArray *existingFiles = [fileManager contentsOfDirectoryAtPath:documentsDirectory error:nil]; 
    NSString *uniquePath; 
    do { 
     CFUUIDRef newUniqueId = CFUUIDCreate(kCFAllocatorDefault); 
     CFStringRef newUniqueIdString = CFUUIDCreateString(kCFAllocatorDefault, newUniqueId); 

     uniquePath = [[documentsDirectory stringByAppendingPathComponent:(__bridge NSString *)newUniqueIdString] stringByAppendingPathExtension:@"png"]; 

     CFRelease(newUniqueId); 
     CFRelease(newUniqueIdString); 
    } while ([existingFiles containsObject:uniquePath]); 

    return uniquePath; 
} 

- (NSString*)saveImage:(UIImage*)image{ 
    NSString *path = [self uniquePath]; 
    NSData *data = UIImagePNGRepresentation(image); 
    [data writeToFile:path atomically:YES]; 
    return [NSString stringWithFormat:@"file://%@",path]; 
} 

- (void) setPhoto:(UIImage *)image { 
    self.photoUrl = [self saveImage:image]; 
}

Ich möchte diesen Thread zu einem Hintergrund schieben , aber ich bin mir nicht sicher, was die Auswirkungen von AFNetworking, Core Data und Messaging im Hinblick auf Thread-Sicherheit sind. Jeder Gedanke?

+1

Zwei Dinge: 1) Verwenden Sie die 'AFImageRequestOperation' Klassenmethode, die die' imageProcessingBlock' Parameter übernimmt, und tun, um die Skalierung von Bildern gibt. 2) Ich würde _against_ empfehlen, Bilder (oder irgendwelche Blobs von Daten wirklich) in Kerndaten zu speichern; Es ist normalerweise eine bessere Idee, die Image-URL zu speichern und 'NSURLCache' oder einen anderen Mechanismus zu verwenden, um diesen gegebenenfalls zu laden. – mattt

+0

Danke Matt, das Verschieben meines Bildverarbeitungscodes in den imageProcessingBlock half. Liebe deine Netzwerkklasse übrigens. –

+0

'AFImageRequestOperation' verwendet einen eigenen Thread, also sollte' [operation start] '* den aktuellen Thread nicht blockieren. – fabb

Antwort

3

Basierend auf Matts Vorschlag verbesserte ich die Benutzeroberfläche, indem ich meinen Anruf wie folgt umarbeitete.

- (void)getPhoto:(NSInteger)type forManagedObject:(MyManagedObject*)object { 

    // download the photo 
    NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:object.photoUrl]]; 
    AFImageRequestOperation *operation = [AFImageRequestOperation 
     imageRequestOperationWithRequest:request 
     imageProcessingBlock:^UIImage *(UIImage *image) { 
      return [image imageByScalingAndCroppingForSize:CGSizeMake(PhotoBlockCellButtonWidth, PhotoBlockCellButtonHeight)]; 
     } 
     cacheName:nil 
     success:^(NSURLRequest *request, NSHTTPURLResponse *response, UIImage *image) { 

      // MyManagedObject has a custom setters (setPhoto:,setThumb:) that save the 
      // images to disk and store the file path in the database 
      object.photo = image; 
      object.thumb = image; 

      NSError *nerror; 
      if (![[DataStore sharedDataStore].managedObjectContext save:&nerror]) { 
       NSLog(@"Whoops, couldn't save: %@", [nerror localizedDescription]); 
       return; 
      } 

      // notify the table view to reload the table 
      [[NSNotificationCenter defaultCenter] postNotificationName:@"ReloadTableView" object:nil];                 
     } 
     failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error) { 
      NSLog(@"Error getting photo"); 
     }]; 
    [operation start]; 
}
4

AFAIK, die Art und Weise Sie Ihre Anfrage in falsch ausgeführt werden:

[operation start]; 

Sie sollten stattdessen die Operation zu einem NSOperationQueue hinzufügen:

NSOperationQueue* operationQueue = [[NSOperationQueue alloc] init]; 
    [operationQueue addOperation:operation]; 

(Sie sollten richtig Speicher-Verwaltung der Warteschlange) .

Dadurch wird Ihre Anfrage asynchron ausgeführt, die Benutzeroberfläche wird nicht blockiert und Sie müssen sich nicht mit Multithreading beschäftigen.

+0

+1 Ich habe vergessen zu erwähnen, dass ich getPhoto bereits über eine NSOperationQueue anrufe, mit der ich meinen gesamten Serverzugriff im Hintergrund verwalte. Matts Lösung half. –

+0

Dies löst Probleme beim Einfrieren – ardavar