6

この関数を使用して、を使用してサーバーに画像をアップロードしていますJSON。そうするために、私は最初に画像をに変換しNSData、次にをNSString使用して変換しBase64ます。この方法は、画像がそれほど大きくない場合は正常に機能しますが、2Mbの画像をアップロードしようとするとクラッシュします。

問題は、メソッドdidReceiveResponseが呼び出されても、サーバーが私の画像を受信しないことです。最初はタイムアウトの問題だと思っていましたが、1000.0に設定しても機能しません。何か案が?御時間ありがとうございます!didReceiveData(null)

これが私の現在のコードです:

 - (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]);

}
4

2 に答える 2

8

私はついにBase64イメージをアップロードして、それをより小さなサブストリングに分割することにしました。そうするために、そして私が多くを必要としていたので、私は各接続にタグを与えるNSURLConnectionsという名前のサブクラスを作成して、それらの間で起こりうる混乱がないようにしました。TagConnection

次に、任意の関数からアクセスする目的でTagConnectionプロパティを作成しました。MyViewControllerご覧のとおり、サーバーからの応答を受信したときに-startAsyncLoad:withTag:、を割り当てて初期化する関数とTagConnection、それを削除する関数があります。-connection:didReceiveData:

関数を参照すると-uploadImage、最初に画像を文字列に変換してから分割し、JSONリクエスト内にチャンクを配置します。変数offsetが文字列の長さより大きくなるまで呼び出されます。これは、すべてのチャンクがアップロードされたことを意味します。

また、サーバーの応答を毎回チェックし、-uploadImage成功を返したときにのみ関数を呼び出すことで、すべてのチャンクが正常にアップロードされたことを証明できます。

これがお役に立てば幸いです。ありがとう。

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
于 2013-03-09T20:41:36.063 に答える
2

これが最後の選択肢だとは思わないでください。これは私の観察です。

そのNSDataは、完全なデータではなく、チャンクで送信する必要があると思います。私はYouTubeビデオアップロードのケースでそのような方法論を見ました。彼らは多くのNSDataのチャンクでNSData(ビデオファイルのNSData)の大きなセットを送信します。

彼らは大きなデータをアップロードするために同じ方法論を使用しています。

だから、YoutubeデータアップロードAPIについてグーグルする必要があります。そしてあなたはその方法、YouTubeアップローダーが使用するものを検索する必要があります。

お役に立てば幸いです。

于 2013-02-16T12:29:06.843 に答える