2013-02-16 12 views
6

ich diese Funktion ist mit einem Bild auf einen Server hochladen JSON verwenden. Um dies zu tun, konvertiere ich zuerst das Bild zu NSData und dann NSString mit Base64. Die Methode funktioniert gut, wenn das Bild nicht sehr groß ist, aber wenn ich versuche, ein 2Mb-Bild hochzuladen, stürzt es ab.Hochladen von großen Bildern mit Base64 und JSON

Das Problem ist, dass der Server mein Bild nicht empfängt, obwohl die didReceiveResponse-Methode aufgerufen wird, sowie die didReceiveData, die (null) zurückgibt. Zuerst dachte ich, es wäre ein Time-Out-Problem, aber selbst wenn es auf 1000 gesetzt wird, funktioniert es immer noch nicht. Irgendeine Idee? Vielen Dank für Ihre Zeit!

Hier ist mein aktueller Code:

- (void) imageRequest { 

    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"http://www.myurltouploadimage.com/services/v1/upload.json"]]; 

    NSString *docDir = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0]; 
    NSString *path = [NSString stringWithFormat:@"%@/design%i.png",docDir, designNum]; 
    NSLog(@"%@",path); 

    NSData *imageData = UIImagePNGRepresentation([UIImage imageWithContentsOfFile:path]); 
    [Base64 initialize]; 
    NSString *imageString = [Base64 encode:imageData]; 

    NSArray *keys = [NSArray arrayWithObjects:@"design",nil]; 
    NSArray *objects = [NSArray arrayWithObjects:imageString,nil]; 
    NSDictionary *jsonDictionary = [NSDictionary dictionaryWithObjects:objects forKeys:keys]; 

    NSError *error; 
    NSData *jsonData = [NSJSONSerialization dataWithJSONObject:jsonDictionary options:kNilOptions error:&error]; 

    [request setHTTPMethod:@"POST"]; 
    [request setValue:[NSString stringWithFormat:@"%d",[jsonData length]] forHTTPHeaderField:@"Content-Length"]; 
    [request setValue:@"application/json" forHTTPHeaderField:@"Accept"]; 
    [request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"]; 
    [request setHTTPBody:jsonData]; 

    [[NSURLConnection alloc] initWithRequest:request delegate:self]; 

    NSLog(@"Image uploaded"); 

} 

- (void) connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response { 

    NSLog(@"didReceiveResponse"); 

} 

- (void) connection:(NSURLConnection *)connection didReceiveData:(NSData *)data { 

    NSLog(@"%@",[NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil]); 

} 
+0

Haben fügen Sie Protokolle auf der PHP-Webseite zu sehen, ob zumindest ist die URL genannt? Wie ein Dateiprotokoll oder SQL-Protokoll? – Vinzius

+1

Eigentlich hat der serverseitige Programmierer mir gesagt, dass, wenn die Website irgendwelche Daten erhält, immer eine Antwort zurückgegeben wird. Also, meine Schlussfolgerung ist, dass er die Anfrage nicht einmal erhält. –

+1

Beiseite: Verwendung von Literalen macht die Dinge einfacher/klarer: 'NSDictionary * jsonDictionary = @ {@" design ": imageString};' – zaph

Antwort

8

entschied ich mich schließlich die Base64 Bild Aufspaltung in der kleinere Teil zu. Um dies zu tun, und wie ich viele NSURLConnections benötigte, erstellte ich eine Unterklasse mit dem Namen TagConnection, die für jede Verbindung ein Tag gibt, so dass es keine mögliche Verwechslung zwischen ihnen gibt.

Dann habe ich eine TagConnection -Eigenschaft in MyViewController mit dem Zweck, den Zugriff von jeder Funktion. Wie Sie sehen können, gibt es die -startAsyncLoad:withTag: Funktion, die die TagConnection Allocs und inits und die -connection:didReceiveData: eine, die es löscht, wenn ich eine Antwort vom Server erhalten.

Mit Bezug auf die -uploadImage Funktion, zuerst, es konvertiert das Bild in eine Zeichenfolge und teilt es dann und legt die Chunks in die JSON-Anfrage. Es wird aufgerufen, bis der variable Offset größer als die Stringlänge ist, was bedeutet, dass alle Chunks hochgeladen wurden.

Sie können auch nachweisen, dass jeder Chunk erfolgreich hochgeladen wurde, indem Sie die Serverantwort jedes Mal überprüfen und nur die -uploadImage-Funktion aufrufen, wenn der Erfolg zurückgegeben wird.

Ich hoffe, das war eine nützliche Antwort. Vielen Dank.

TagConnection.h

@interface TagConnection : NSURLConnection { 
    NSString *tag; 
} 

@property (strong, nonatomic) NSString *tag; 

- (id)initWithRequest:(NSURLRequest *)request delegate:(id)delegate startImmediately:(BOOL)startImmediately tag:(NSString*)tag; 

@end 

TagConnection.m

#import "TagConnection.h" 

@implementation TagConnection 

@synthesize tag; 

- (id)initWithRequest:(NSURLRequest *)request delegate:(id)delegate startImmediately:(BOOL)startImmediately tag:(NSString*)tag { 
    self = [super initWithRequest:request delegate:delegate startImmediately:startImmediately]; 

    if (self) { 
     self.tag = tag; 
    } 
    return self; 
} 

- (void)dealloc { 
    [tag release]; 
    [super dealloc]; 
} 

@end 

MyViewController.h

#import "TagConnection.h" 

@interface MyViewController : UIViewController 

@property (strong, nonatomic) TagConnection *conn; 

MyViewController.m

#import "MyViewController.h" 

@interface MyViewController() 

@end 

@synthesize conn; 

bool stopSending = NO; 
int chunkNum = 1; 
int offset = 0; 

- (IBAction) uploadImageButton:(id)sender { 

    [self uploadImage]; 

} 

- (void) startAsyncLoad:(NSMutableURLRequest *)request withTag:(NSString *)tag { 

    self.conn = [[[TagConnection alloc] initWithRequest:request delegate:self startImmediately:YES tag:tag] autorelease]; 

} 

- (void) uploadImage { 

    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"http://www.mywebpage.com/upload.json"] cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:1000.0]; 

    NSString *docDir = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0]; 
    NSString *path = [NSString stringWithFormat:@"%@/design%i.png", docDir, designNum]; 
    NSLog(@"%@",path); 

    NSData *imageData = UIImagePNGRepresentation([UIImage imageWithContentsOfFile:path]); 
    [Base64 initialize]; 
    NSString *imageString = [Base64 encode:imageData]; 

    NSUInteger length = [imageString length]; 
    NSUInteger chunkSize = 1000; 

    NSUInteger thisChunkSize = length - offset > chunkSize ? chunkSize : length - offset; 
    NSString *chunk = [imageString substringWithRange:NSMakeRange(offset, thisChunkSize)]; 
    offset += thisChunkSize; 

    NSArray *keys = [NSArray arrayWithObjects:@"design",@"design_id",@"fragment_id",nil]; 
    NSArray *objects = [NSArray arrayWithObjects:chunk,@"design_id",[NSString stringWithFormat:@"%i", chunkNum],nil]; 
    NSDictionary *jsonDictionary = [NSDictionary dictionaryWithObjects:objects forKeys:keys]; 

    NSError *error; 
    NSData *jsonData = [NSJSONSerialization dataWithJSONObject:jsonDictionary options:kNilOptions error:&error]; 

    [request setHTTPMethod:@"POST"]; 
    [request setValue:[NSString stringWithFormat:@"%d",[jsonData length]] forHTTPHeaderField:@"Content-Length"]; 
    [request setValue:@"application/json" forHTTPHeaderField:@"Accept"]; 
    [request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"]; 
    [request setHTTPBody:jsonData]; 

    [self startAsyncLoad:request withTag:[NSString stringWithFormat:@"tag%i",chunkNum]]; 

    if (offset > length) { 
     stopSending = YES; 
    } 

} 

- (void) connection:(NSURLConnection *)connection didReceiveData:(NSData *)data { 

    NSError *error; 
    NSArray *responseData = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&error]; 
    if (!responseData) { 
     NSLog(@"Error parsing JSON: %@", error); 
    } else { 
     if (stopSending == NO) { 
      chunkNum++; 
      [self.conn cancel]; 
      self.conn = nil; 
      [self uploadImage]; 
     } else { 
      NSLog(@"---------Image sent---------"); 
     } 
    } 

} 

@end 
+1

Kannst du bitte auch für den serverseitigen Code helfen? Ich kann das nicht auf der PHP-Seite! –

+0

Es tut mir leid, aber das liegt nicht an mir. –

2

Bitte denken Sie nicht, dass dies die letzte Option ist, das ist nur meine Beobachtung.

Ich denke, man sollte, dass NSData anstelle von kompletten Daten in Blöcken senden. Ich habe solche Methodik in YouTube Video Upload Fall gesehen. Sie senden die große Menge von NSData (NSData der Videodatei) in Chunks von vielen NSData.

Sie verwendet die gleiche Methode für die großen Daten hochladen.

sollten über die Youtube Daten Hochladen API.And Sie sollten diese Methode herausfinden, verwendet so tun google YouTube Uploader.

Ich hoffe, dass es Ihnen helfen kann.

+0

So ähnlich ?: http://stackoverflow.com/questions/2899020/split-nsdata-objects-into-other-nsdata-objects-with-a-given-size –

Verwandte Themen