上传使用Base64和JSON大型图片 [英] Uploading large images using Base64 and JSON

查看:252
本文介绍了上传使用Base64和JSON大型图片的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用这个功能来上传图片到使用 JSON 的服务器。为了做到这一点,我首先将图像通过转换为的NSData 再到的NSString Base64编码。当图像不是非常大,但是当我尝试上传2MB的图像,它崩溃的方法,工作正常。

问题是,该服务器没有收到即使 didReceiveResponse 方法被调用,以及在 didReceiveData 返回(空)。起初我以为这是一个超时问题,但即使将它设置为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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆