iphone - Upload with Buffer iOS 7 -
i trying implement upload random data , measure speed. generating random nsdata this:
void * bytes = malloc(""); nsdata * mydata = [nsdata datawithbytes:bytes length:"bytes"]; free("bytes");
but there memory problems if want upload big file...
my upload process this:
nsurlsessionconfiguration *sessionconfig = [nsurlsessionconfiguration defaultsessionconfiguration]; nsurlsession *session = [nsurlsession sessionwithconfiguration:sessionconfig delegate:self delegatequeue:nil]; nsurl * urll = [nsurl urlwithstring:upload_server]; nsmutableurlrequest * urlrequest = [nsmutableurlrequest requestwithurl:urll]; [urlrequest sethttpmethod:@"post"]; [urlrequest addvalue:@"keep-alive" forhttpheaderfield:@"connection"]; nsstring *boundary = @"*****"; nsstring *contenttype = [nsstring stringwithformat:@"multipart/form-data; boundary=%@",boundary]; [urlrequest addvalue:contenttype forhttpheaderfield: @"content-type"]; nsmutabledata *body = [nsmutabledata data]; [body appenddata:[[nsstring stringwithformat:@"\r\n--%@\r\n",boundary] datausingencoding:nsutf8stringencoding]]; [body appenddata:[@"content-type: application/octet-stream\r\n\r\n" datausingencoding:nsutf8stringencoding]]; [body appenddata:[[nsstring stringwithformat:@"\r\n--%@--\r\n",boundary] datausingencoding:nsutf8stringencoding]]; // setting body of post reqeust [urlrequest sethttpbody:body]; void * bytes = malloc(250000000); nsdata * uploaddata = [nsdata datawithbytes:bytes length:250000000]; free(bytes); ultask = [session uploadtaskwithrequest:urlrequest fromdata:uploaddata]; [ultask resume];
is there way upload buffer or something?! generate small data, upload , generate new 1 , upload again?!
i suggest start upload , keep sending data. can avoid creation of 250mb buffer, using uploadtaskwithstreamedrequest
, create nsinputstream
subclass keeps providing more data until tell stop. can implement urlsession:task:didsendbodydata:totalbytessent:totalbytesexpectedtosend:
monitor progress of upload (so can presumably monitor speed data being sent).
anyway, create upload request:
@interface viewcontroller () <nsurlsessiondelegate, nsurlsessiontaskdelegate> @property (nonatomic, strong) customstream *inputstream; @end @implementation viewcontroller - (void)viewdidload { [super viewdidload]; self.inputstream = [[customstream alloc] init]; nsurl *url = [nsurl urlwithstring:kurlstring]; nsmutableurlrequest *request = [nsmutableurlrequest requestwithurl:url]; [request sethttpmethod:@"post"]; nsurlsessionconfiguration *configuration = [nsurlsessionconfiguration defaultsessionconfiguration]; nsurlsession *session = [nsurlsession sessionwithconfiguration:configuration delegate:self delegatequeue:nil]; nsurlsessionuploadtask *task = [session uploadtaskwithstreamedrequest:request]; [task resume]; // don't know how want finish upload, i'm going // stop after 10 seconds dispatch_after(dispatch_time(dispatch_time_now, (int64_t)(10.0 * nsec_per_sec)), dispatch_get_main_queue(), ^{ self.inputstream.finished = yes; }); }
you have implement appropriate delegate methods:
#pragma mark - nsurlsessiontaskdelegate - (void)urlsession:(nsurlsession *)session task:(nsurlsessiontask *)task didsendbodydata:(int64_t)bytessent totalbytessent:(int64_t)totalbytessent totalbytesexpectedtosend:(int64_t)totalbytesexpectedtosend { nslog(@"%lld %lld %lld", bytessent, totalbytessent, totalbytesexpectedtosend); } - (void)urlsession:(nsurlsession *)session task:(nsurlsessiontask *)task neednewbodystream:(void (^)(nsinputstream *bodystream))completionhandler { completionhandler(self.inputstream); } - (void)urlsession:(nsurlsession *)session task:(nsurlsessiontask *)task didcompletewitherror:(nserror *)error { nslog(@"%s: error = %@; data = %@", __pretty_function__, error, [[nsstring alloc] initwithdata:self.responsedata encoding:nsutf8stringencoding]); } #pragma mark - nsurlsessiondatadelegate - (void)urlsession:(nsurlsession *)session datatask:(nsurlsessiondatatask *)datatask didreceiveresponse:(nsurlresponse *)response completionhandler:(void (^)(nsurlsessionresponsedisposition disposition))completionhandler { self.responsedata = [nsmutabledata data]; completionhandler(nsurlsessionresponseallow); } - (void)urlsession:(nsurlsession *)session datatask:(nsurlsessiondatatask *)datatask didreceivedata:(nsdata *)data { [self.responsedata appenddata:data]; }
and customstream
:
static nsinteger const kbuffersize = 32768; @interface customstream : nsinputstream @property (nonatomic, readonly) nsstreamstatus streamstatus; @property (nonatomic, getter = isfinished) bool finished; @end @interface customstream () @property (nonatomic) nsstreamstatus streamstatus; @property (nonatomic) void *buffer; @end @implementation customstream - (instancetype)init { self = [super init]; if (self) { _buffer = malloc(kbuffersize); nsassert(_buffer, @"unable create buffer"); memset(_buffer, 0, kbuffersize); } return self; } - (void)dealloc { if (_buffer) { free(_buffer); self.buffer = null; } } - (void)open { self.streamstatus = nsstreamstatusopen; } - (void)close { self.streamstatus = nsstreamstatusclosed; } - (nsinteger)read:(uint8_t *)buffer maxlength:(nsuinteger)len { if ([self isfinished]) { if (self.streamstatus == nsstreamstatusopen) { self.streamstatus = nsstreamstatusatend; } return 0; } nsuinteger bytestocopy = min(len, kbuffersize); memcpy(buffer, _buffer, bytestocopy); return bytestocopy; } - (bool)getbuffer:(uint8_t **)buffer length:(nsuinteger *)len { return no; } - (bool)hasbytesavailable { return self.streamstatus == nsstreamstatusopen; } - (void)scheduleinrunloop:(__unused nsrunloop *)arunloop formode:(__unused nsstring *)mode {} - (void)removefromrunloop:(__unused nsrunloop *)arunloop formode:(__unused nsstring *)mode {} #pragma mark undocumented cfreadstream bridged methods - (void)_scheduleincfrunloop:(__unused cfrunloopref)arunloop formode:(__unused cfstringref)amode {} - (void)_unschedulefromcfrunloop:(__unused cfrunloopref)arunloop formode:(__unused cfstringref)amode {} - (bool)_setcfclientflags:(__unused cfoptionflags)inflags callback:(__unused cfreadstreamclientcallback)incallback context:(__unused cfstreamclientcontext *)incontext { return no; } @end
i'd suggest refer bj homer's article subclassing nsinputstream of background on few of cryptic methods in nsinputstream
subclass.
Comments
Post a Comment