All Products
Search
Document Center

Object Storage Service:Multipart upload (iOS SDK)

Last Updated:Feb 27, 2026

Object Storage Service (OSS) lets you split a large object into multiple parts and upload them separately. After all parts are uploaded, call the CompleteMultipartUpload operation to assemble them into a single object.

Multipart upload is ideal for large files or unstable network conditions. Upload parts in parallel over a fast network to maximize throughput, or use smaller parts over an unreliable network to minimize retry overhead.

Prerequisites

Before you begin, make sure that you have:

Limits

ItemLimit
Minimum part size100 KB (except the last part)
Default part size (OSSMultipartUploadRequest)256 KB
Part number range1 to 10,000
Maximum parts returned per ListParts request1,000

Upload a local file (recommended)

OSSMultipartUploadRequest handles the multipart upload workflow automatically. It splits the file, uploads each part, and completes the upload. Use this approach unless you need fine-grained control over individual parts.

// Specify the bucket name. Example: examplebucket.
NSString *bucketName = @"examplebucket";
// Specify the full path of the object. Do not include the bucket name.
// Example: exampledir/exampleobject.txt.
NSString *objectKey = @"exampledir/exampleobject.txt";

OSSMultipartUploadRequest * multipartUploadRequest = [OSSMultipartUploadRequest new];
multipartUploadRequest.bucketName = bucketName;
multipartUploadRequest.objectKey = objectKey;
// Set the part size in bytes. Default: 256 KB.
multipartUploadRequest.partSize = 1024 * 1024;
multipartUploadRequest.uploadProgress = ^(int64_t bytesSent, int64_t totalByteSent, int64_t totalBytesExpectedToSend) {
    NSLog(@"progress: %lld, %lld, %lld", bytesSent, totalByteSent, totalBytesExpectedToSend);
};

multipartUploadRequest.uploadingFileURL = [[NSBundle mainBundle] URLForResource:@"wangwang" withExtension:@"zip"];
OSSTask * multipartTask = [client multipartUpload:multipartUploadRequest];
[[multipartTask continueWithBlock:^id(OSSTask *task) {
    if (task.error) {
        NSLog(@"error: %@", task.error);
    } else {
        NSLog(@"Upload file success");
    }
    return nil;
}] waitUntilFinished];

Key parameters:

ParameterDescription
bucketNameTarget bucket name
objectKeyFull object path, excluding the bucket name
partSizeSize of each part in bytes. Default: 256 KB
uploadProgressCallback that reports bytes sent, total bytes sent, and total bytes expected
uploadingFileURLLocal file URL to upload

Step-by-step multipart upload

For scenarios that require fine-grained control, such as custom retry logic per part or parallel uploads with a specific concurrency level, use the three-step multipart upload process directly.

How it works

  1. Call InitiateMultipartUpload to start a multipart upload task and get an upload ID.

  2. Call UploadPart to upload each part. Parts can be uploaded sequentially or in parallel.

  3. Call CompleteMultipartUpload to assemble all parts into a single object.

Part position within the object is determined by the part number you specify during upload. Parts do not need to be uploaded in order.

Complete example

__block NSString * uploadId = nil;
__block NSMutableArray * partInfos = [NSMutableArray new];
// Specify the bucket name. Example: examplebucket.
NSString * uploadToBucket = @"examplebucket";
// Specify the full path of the object. Do not include the bucket name.
// Example: exampledir/exampleobject.txt.
NSString * uploadObjectkey = @"exampledir/exampleobject.txt";

// Step 1: Initiate the multipart upload task.
OSSInitMultipartUploadRequest * init = [OSSInitMultipartUploadRequest new];
init.bucketName = uploadToBucket;
init.objectKey = uploadObjectkey;
// init.contentType = @"application/octet-stream";

OSSTask * initTask = [client multipartUploadInit:init];
[initTask waitUntilFinished];
if (!initTask.error) {
    OSSInitMultipartUploadResult * result = initTask.result;
    // The upload ID uniquely identifies this multipart upload task.
    // Use it to upload parts, list parts, or cancel the task.
    uploadId = result.uploadId;
} else {
    NSLog(@"multipart upload failed, error: %@", initTask.error);
    return;
}

// Step 2: Upload each part.
NSString * filePath = @"<filepath>";
uint64_t fileSize = [[[NSFileManager defaultManager] attributesOfItemAtPath:filePath error:nil] fileSize];
int chuckCount = 10;
uint64_t offset = fileSize/chuckCount;
for (int i = 1; i <= chuckCount; i++) {
    OSSUploadPartRequest * uploadPart = [OSSUploadPartRequest new];
    uploadPart.bucketName = uploadToBucket;
    uploadPart.objectkey = uploadObjectkey;
    uploadPart.uploadId = uploadId;
    uploadPart.partNumber = i; // Part numbers start from 1.

    NSFileHandle* readHandle = [NSFileHandle fileHandleForReadingAtPath:filePath];
    [readHandle seekToFileOffset:offset * (i -1)];

    NSData* data = [readHandle readDataOfLength:offset];
    uploadPart.uploadPartData = data;

    OSSTask * uploadPartTask = [client uploadPart:uploadPart];

    [uploadPartTask waitUntilFinished];

    if (!uploadPartTask.error) {
        OSSUploadPartResult * result = uploadPartTask.result;
        uint64_t fileSize = [[[NSFileManager defaultManager] attributesOfItemAtPath:uploadPart.uploadPartFileURL.absoluteString error:nil] fileSize];
        [partInfos addObject:[OSSPartInfo partInfoWithPartNum:i eTag:result.eTag size:fileSize]];
    } else {
        NSLog(@"upload part error: %@", uploadPartTask.error);
        return;
    }
}

// Step 3: Complete the multipart upload.
OSSCompleteMultipartUploadRequest * complete = [OSSCompleteMultipartUploadRequest new];
complete.bucketName = uploadToBucket;
complete.objectKey = uploadObjectkey;
complete.uploadId = uploadId;
complete.partInfos = partInfos;

OSSTask * completeTask = [client completeMultipartUpload:complete];

[[completeTask continueWithBlock:^id(OSSTask *task) {
    if (!task.error) {
        OSSCompleteMultipartUploadResult * result = task.result;
        // ...
    } else {
        // ...
    }
    return nil;
}] waitUntilFinished];

Replace <filepath> with the absolute path to the local file.

Concurrency tuning

When uploading parts in parallel, set the concurrency level based on network conditions and device load. A higher concurrency level does not always result in faster uploads. Use larger parts when the network is stable, and smaller parts when it is not.

List uploaded parts

Call the listParts method to retrieve all uploaded parts for a specific multipart upload task. The upload ID is required.

OSSListPartsRequest * listParts = [OSSListPartsRequest new];
// Specify the bucket name. Example: examplebucket.
listParts.bucketName = @"examplebucket";
// Specify the full path of the object. Do not include the bucket name.
// Example: exampledir/exampleobject.txt.
listParts.objectKey = @"exampledir/exampleobject.txt";
// Specify the upload ID. Get it from the InitiateMultipartUpload response
// before calling CompleteMultipartUpload.
listParts.uploadId = @"0004B999EF518A1FE585B0C9****";

OSSTask * listPartTask = [client listParts:listParts];

[listPartTask continueWithBlock:^id(OSSTask *task) {
    if (!task.error) {
        NSLog(@"list part result success!");
        OSSListPartsResult * listPartResult = task.result;
        for (NSDictionary * partInfo in listPartResult.parts) {
            NSLog(@"each part: %@", partInfo);
        }
    } else {
        NSLog(@"list part result error: %@", task.error);
    }
    return nil;
}];
By default, if more than 1,000 parts exist for a multipart upload, OSS returns the first 1,000 parts. In the response, IsTruncated is set to false and NextPartNumberMarker indicates the starting position for the next list request.

Cancel a multipart upload task

Call the abortMultipartUpload method to cancel a multipart upload task and delete all uploaded parts.

OSSAbortMultipartUploadRequest * abort = [OSSAbortMultipartUploadRequest new];
// Specify the bucket name. Example: examplebucket.
abort.bucketName = @"examplebucket";
// Specify the full path of the object. Do not include the bucket name.
// Example: exampledir/exampleobject.txt.
abort.objectKey = @"exampledir/exampleobject.txt";
// Specify the upload ID. Get it from the InitiateMultipartUpload response.
abort.uploadId = @"0004B999EF518A1FE585B0C9****";

OSSTask * abortTask = [client abortMultipartUpload:abort];

[abortTask waitUntilFinished];

if (!abortTask.error) {
    OSSAbortMultipartUploadResult * result = abortTask.result;
    uploadId = result.uploadId;
} else {
    NSLog(@"multipart upload failed, error: %@", abortTask.error);
    return;
}
Important

If you upload parts but do not call CompleteMultipartUpload, the parts remain in storage and incur costs. Either call AbortMultipartUpload to delete them, or configure a lifecycle rule to automatically clean up incomplete multipart uploads.

References