2013-02-16 37 views
6

Tôi đang sử dụng chức năng này để tải hình ảnh lên máy chủ bằng cách sử dụng JSON. Để làm như vậy, trước tiên tôi chuyển đổi hình ảnh thành NSData và sau đó đến NSString bằng cách sử dụng Base64. Phương pháp này hoạt động tốt khi hình ảnh không phải là rất lớn nhưng khi tôi cố gắng tải lên một hình ảnh 2Mb, nó bị treo.Tải lên hình ảnh lớn bằng Base64 và JSON

Sự cố là máy chủ không nhận được hình ảnh của tôi mặc dù phương thức didReceiveResponse được gọi cũng như didReceiveData trả về (null). Lúc đầu, tôi nghĩ rằng đó là một vấn đề thời gian ra, nhưng thậm chí thiết lập nó đến 1000.0 nó vẫn không hoạt động. Bất kỳ ý tưởng? Cảm ơn vì đã dành thời gian cho tôi!

Đây là mã hiện tại của tôi:

- (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

Bạn có thêm bất kỳ bản ghi trên trang web php để xem, ít nhất, các url được gọi là? như nhật ký tệp hoặc nhật ký sql? – Vinzius

+1

Thực ra, lập trình viên phía máy chủ đã nói với tôi rằng nếu trang web nhận được bất kỳ dữ liệu nào, một phản hồi luôn được trả về. Vì vậy, kết luận của tôi là anh ta thậm chí không nhận được yêu cầu. –

+1

Ngoài ra: việc sử dụng chữ giúp mọi thứ trở nên dễ dàng/rõ ràng hơn: 'NSDictionary * jsonDictionary = @ {@" design ": imageString};' – zaph

Trả lời

8

Cuối cùng tôi đã quyết định tải lên hình ảnh Base64 tách nó thành các phần nhỏ hơn. Để làm như vậy, và khi tôi cần nhiều NSURLConnections, tôi đã tạo một lớp con có tên là TagConnection cung cấp thẻ cho từng kết nối để không có sự nhầm lẫn nào giữa chúng.

Sau đó, tôi đã tạo thuộc tính TagConnection trong MyViewController với mục đích truy cập nó từ bất kỳ chức năng nào. Như bạn có thể thấy, có chức năng -startAsyncLoad:withTag: mà allocs và nhập vào các TagConnection-connection:didReceiveData: một trong đó xóa nó khi tôi nhận được một phản hồi từ máy chủ.

Tham chiếu đến hàm -uploadImage, trước tiên, nó chuyển đổi hình ảnh thành chuỗi và sau đó tách nó ra và đặt các khối bên trong yêu cầu JSON. Nó được gọi cho đến khi độ lệch biến lớn hơn chiều dài chuỗi có nghĩa là tất cả các khối đã được tải lên.

Bạn cũng có thể chứng minh rằng mọi đoạn đã được tải lên thành công bằng cách kiểm tra phản hồi của máy chủ mỗi lần và chỉ gọi hàm -uploadImage khi nó trả về thành công.

Tôi hy vọng đây là câu trả lời hữu ích. Cảm ơn.

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

Bạn có thể vui lòng trợ giúp mã phía máy chủ không? Tôi không thể làm điều này trong php! –

+0

Tôi xin lỗi nhưng điều đó không tùy thuộc vào tôi. –

2

Xin đừng nghĩ rằng đây là lựa chọn cuối cùng, đây chỉ là quan sát của tôi.

Tôi nghĩ bạn nên gửi NSData đó theo khối thay vì hoàn thành Dữ liệu. Tôi đã xem phương pháp như vậy trong trường hợp Tải lên video của YouTube. Họ gửi tập hợp lớn NSData (NSData của tệp video) trong Phần của nhiều NSData.

Chúng sử dụng Phương pháp tương tự để tải lên dữ liệu lớn.

Vì vậy, hãy làm google về API tải lên dữ liệu Youtube. Và bạn nên tìm kiếm phương pháp đó, Trình tải lên của YouTube sử dụng.

Tôi hy vọng nó có thể giúp bạn.

+0

Một cái gì đó như thế ?: http://stackoverflow.com/questions/2899020/split-nsdata-objects-into-other-nsdata-objects-with-a-given-size –

Các vấn đề liên quan