上传使用Base64和JSON大型图片 [英] Uploading large images using Base64 and JSON
问题描述
我使用这个功能来上传图片到使用 JSON
的服务器。为了做到这一点,我首先将图像通过转换为的NSData code>再到
的NSString
Base64编码
。当图像不是非常大,但是当我尝试上传2MB的图像,它崩溃的方法,工作正常。
问题是,该服务器没有收到即使 didReceiveResponse
方法被调用,以及在 didReceiveData $ C我的形象$ C>返回
(空)
。起初我以为这是一个超时问题,但即使将它设置为1000.0它仍然无法正常工作。任何想法?感谢您的时间!
下面是我目前的code:
- (无效){imageRequest NSMutableURLRequest *请求= [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@http://www.myurltouploadimage.com/services/v1/upload.json]]; 的NSString * docDir = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,是)objectAtIndex:0];
* NSString的路径= [的NSString stringWithFormat:@%@ /设计%i.png,docDir,designNum]
的NSLog(@%@,路径); NSData的*为imageData = UIImagePNGRe presentation([UIImage的imageWithContentsOfFile:路径]);
[Base64的初始化]
* NSString的=和imagestring [Base64的EN code:为imageData]; NSArray的*键= [NSArray的arrayWithObjects:@设计,零]
NSArray的对象* = [NSArray的arrayWithObjects:和imagestring,无]
*的NSDictionary = jsonDictionary [NSDictionary的dictionaryWithObjects:对象forKeys:键]; NSError *错误;
NSData的* jsonData = [NSJSONSerialization dataWithJSONObject:jsonDictionary选项:kNilOptions错误:&放大器;错误] [要求setHTTPMethod:@POST];
[申请的setValue:[的NSString stringWithFormat:@%D,[jsonData长度] forHTTPHeaderField:@内容长度];
[申请的setValue:@应用程序/ JSONforHTTPHeaderField:@接受];
[申请的setValue:@应用程序/ JSONforHTTPHeaderField:@的Content-Type];
[要求setHTTPBody:jsonData]; [[NSURLConnection的页头] initWithRequest:要求委托:自我]; 的NSLog(@图片上传);} - (无效)连接:(NSURLConnection的*)连接didReceiveResponse:(NSURLResponse *){响应 的NSLog(@didReceiveResponse);} - (无效)连接:(NSURLConnection的*)连接didReceiveData:(NSData的*)数据{ 的NSLog(@%@,[NSJSONSerialization JSONObjectWithData:数据选项:kNilOptions错误:零]);}
我终于决定为Base64图像分割上传成更小的子串。为了做到这一点,当我需要多少 NSURLConnections
,我创建了一个名为 TagConnection
子类,给出了一个标记为每个连接,以便有它们之间没有可能的混淆。
然后,我创建了 MyViewController
A TagConnection
属性与任何函数访问它的目的。正如你所看到的,还有的 -startAsyncLoad:withTag:
函数allocs和inits的 TagConnection
和 -connection:didReceiveData:
其中之一删除它,当我收到来自服务器的响应
参照 -uploadImage
功能,首先它转换成图像字符串,然后分割它,并把大块的JSON请求中。它被称为直到变量偏移大于字符串长度,这意味着所有的块已被上传大。
您也可以证明,每块由已每次检查服务器响应,只调用 -uploadImage
函数,当它返回成功上传成功。
我希望这是一个有用的答案。谢谢。
TagConnection.h
@interface TagConnection:NSURLConnection的{
* NSString的标签;
}@property(强,非原子)的NSString *标签; - (ID)initWithRequest:(*的NSURLRequest)申请委托:(ID)代表startImmediately:(BOOL)startImmediately标签:(* NSString的)标签;@结束
TagConnection.m
#进口TagConnection.h@implementation TagConnection@synthesize标签; - (ID)initWithRequest:(*的NSURLRequest)申请委托:(ID)代表startImmediately:(BOOL)startImmediately标签:(* NSString的)标签{
自= [超级initWithRequest:要求委托:委托startImmediately:startImmediately]; 如果(个体经营){
self.tag =标签;
}
返回自我;
} - (无效){的dealloc
[标签发布]
[超级的dealloc];
}@结束
MyViewController.h
#进口TagConnection.h@interface MyViewController:UIViewController中@property(强,非原子)TagConnection *康恩;
MyViewController.m
#进口MyViewController.h@interface MyViewController()@结束@synthesize康涅狄格州;布尔stopSending = NO;
INT chunkNum = 1;
INT偏移= 0; - (IBAction为)uploadImageButton:(ID)发送{ [个体经营uploadImage]} - (无效)startAsyncLoad:(NSMutableURLRequest *)要求withTag:(* NSString的)标签{ self.conn = [[[TagConnection页头] initWithRequest:要求委托:自我startImmediately:YES标签:标签]自动释放];} - (无效){uploadImage NSMutableURLRequest *请求= [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@http://www.mywebpage.com/upload.json]的CachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:1000.0]; 的NSString * docDir = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,是)objectAtIndex:0];
* NSString的路径= [的NSString stringWithFormat:@%@ /设计%i.png,docDir,designNum]
的NSLog(@%@,路径); NSData的*为imageData = UIImagePNGRe presentation([UIImage的imageWithContentsOfFile:路径]);
[Base64的初始化]
* NSString的=和imagestring [Base64的EN code:为imageData]; NSUInteger长度= [和imagestring长度]
NSUInteger CHUNKSIZE = 1000; NSUInteger thisChunkSize =长度 - 偏移> CHUNKSIZE? CHUNKSIZE:长度 - 偏移;
的NSString *块= [和imagestring substringWithRange:NSMakeRange(偏移,thisChunkSize)];
胶印+ = thisChunkSize; NSArray的*键= [NSArray的arrayWithObjects:@设计,@design_id,@fragment_id零]
NSArray的对象* = [NSArray的arrayWithObjects:大块,@design_id,[的NSString stringWithFormat:@%i的,chunkNum],无]
*的NSDictionary = jsonDictionary [NSDictionary的dictionaryWithObjects:对象forKeys:键]; NSError *错误;
NSData的* jsonData = [NSJSONSerialization dataWithJSONObject:jsonDictionary选项:kNilOptions错误:&放大器;错误] [要求setHTTPMethod:@POST];
[申请的setValue:[的NSString stringWithFormat:@%D,[jsonData长度] forHTTPHeaderField:@内容长度];
[申请的setValue:@应用程序/ JSONforHTTPHeaderField:@接受];
[申请的setValue:@应用程序/ JSONforHTTPHeaderField:@的Content-Type];
[要求setHTTPBody:jsonData]; [个体经营startAsyncLoad:要求withTag:[的NSString stringWithFormat:@标签%I,chunkNum]]; 如果(偏移>长度){
stopSending = YES;
}} - (无效)连接:(NSURLConnection的*)连接didReceiveData:(NSData的*)数据{ NSError *错误;
NSArray的* responseData = [NSJSONSerialization JSONObjectWithData:数据选项:kNilOptions错误:&放大器;错误]
如果(!responseData){
的NSLog(@错误解析JSON:%@,错误);
}其他{
如果(stopSending == NO){
chunkNum ++;
[self.conn取消]
self.conn =零;
[个体经营uploadImage]
}其他{
的NSLog(@---------图片发送---------);
}
}}@结束
I am using this function to upload an image to a server using JSON
. In order to do so, I first convert the image to NSData
and then to NSString
using Base64
. The method works fine when the image is not very large but when I try to upload a 2Mb image, it crashes.
The problem is that the server doesn't receive my image even though the didReceiveResponse
method is called as well as the didReceiveData
which returns (null)
. At first I thought it was a time out issue but even setting it to 1000.0 it still doesn't work. Any idea? Thanks for your time!
Here's my current 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]);
}
I finally decided to upload the Base64 image splitting it into smaller substrings. In order to do so, and as I needed many NSURLConnections
, I created a subclass named TagConnection
which gives a tag for each connection so that there's no possible confusion between them.
Then I created a TagConnection
property in MyViewController
with the purpose of accessing it from any function. As you can see, there's the -startAsyncLoad:withTag:
function that allocs and inits the TagConnection
and the -connection:didReceiveData:
one which deletes it when I receive a response from the server.
Referring to the -uploadImage
function, firstly, it converts the image into string and then splits it and put the chunks inside the JSON request. It is called until the variable offset is larger than the string length which means that all the chunks have been uploaded.
You can also prove that every chunk has been successfully uploaded by checking the server response every time and only calling the -uploadImage
function when it returns success.
I hope this has been a useful answer. Thanks.
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
这篇关于上传使用Base64和JSON大型图片的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!