I've looked into a good number of articles on how to do a multipart/form-data POST on iOS, but none really explain what to do if there were normal parameters as well as the file upload.

NSURL *url = [NSURL URLWithString:requestString];
        NSMutableURLRequest* urlRequest = [NSMutableURLRequest requestWithURL: url cachePolicy: NSURLRequestReloadIgnoringCacheData timeoutInterval:60.0];
        [urlRequest setHTTPMethod:@"POST"];
        NSOperationQueue *queue = [[NSOperationQueue alloc] init];

        [urlRequest setValue:MainHEADER forHTTPHeaderField:@"Auth"];

        NSData *imageData = UIImageJPEGRepresentation(image, 0.8);
        image = nil;
        NSString charset = (NSString )CFStringConvertEncodingToIANACharSetName(CFStringConvertNSStringEncodingToEncoding(NSUTF8StringEncoding));
        NSString *boundary = @"0xKhTmLbOuNdArY";
        NSString *endBoundary = [NSString stringWithFormat:@"\r\n--%@\r\n", boundary];
        NSString *contentType = [NSString stringWithFormat:@"multipart/form-data; charset=%@; boundary=%@", charset, boundary];
        [urlRequest addValue:contentType forHTTPHeaderField: @"Content-Type"];
        NSMutableData *tempPostData = [NSMutableData data];

        // Param in body
        [parameters enumerateKeysAndObjectsUsingBlock:^(NSString parameterKey, NSString parameterValue, BOOL *stop) {
            [tempPostData appendData:[[NSString stringWithFormat:@"--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
            [tempPostData appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"\r\n\r\n", parameterKey] dataUsingEncoding:NSUTF8StringEncoding]];
            [tempPostData appendData:[[NSString stringWithFormat:@"%@\r\n", parameterValue] dataUsingEncoding:NSUTF8StringEncoding]];
        }];

        // param in body
    if (imageData != nil)
    {
        [tempPostData appendData:[[NSString stringWithFormat:@"--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
        // Sample Key Value for data
        [tempPostData appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"\r\n\r\n", @"image"] dataUsingEncoding:NSUTF8StringEncoding]];
        //    [[tempPostData appendData:@"Value_Param"] dataUsingEncoding:NSUTF8StringEncoding]];
        [tempPostData appendData:[endBoundary dataUsingEncoding:NSUTF8StringEncoding]];
        // Sample file to send as data
        [tempPostData appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"image\"; filename=\"%@\"\r\n", @".jpg"] dataUsingEncoding:NSUTF8StringEncoding]];
        [tempPostData appendData:[@"Content-Type: application/octet-stream\r\n\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
        [tempPostData appendData:imageData];
        [tempPostData appendData:[[NSString stringWithFormat:@"\r\n--%@--\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
    }

        [urlRequest setHTTPBody:tempPostData];
        tempPostData = nil;

        [NSURLConnection sendAsynchronousRequest:urlRequest queue:queue completionHandler:^(NSURLResponse response, NSData data, NSError *error)
         {
             dispatch_async(dispatch_get_main_queue(), ^{

             });
             if (error)
             {
                 NSLog(@"Error,%@", [error localizedDescription]);
                 failureBlock([error localizedDescription]);
             }
             else
             {
                 NSError *errorJson;
                 NSDictionary *JSON = [NSJSONSerialization JSONObjectWithData:data options: NSJSONReadingMutableContainers error: &errorJson];
                 data = nil;
                 errorJson = nil;
                 response = nil;
                 error = nil;
                 NSLog(@"Json = %@",JSON);
                 dispatch_async(dispatch_get_main_queue(), ^{
                     successBlock(JSON);
                 });
                 JSON = nil;
             }
         }];
        requestString = nil;
        url = nil;
        urlRequest = nil;
        queue = nil;

This is my code working in the objective-c but i don't know how to do in the swift

I have used the multipart/form-data POST on iOS & I had written the following code and it is uploading data but not image data

I have looked the code with armofire but we need to do without it and with the session url request

1 Answers

0
Sagar Chauhan On

I have following code which are used in my current project to upload image on server using multipart form data as we as when normal parameters.

// Create function which accept Parameters and UIImage type
// Completion block with return [String: Any] or Error
func addProfileDetails(parameters: Parameters, image: UIImage?, completion: @escaping (ProfileImageModel?, Error?) -> Void) {

    // If image not nil then code with parameters and image
    if image != nil {

        Alamofire.upload( multipartFormData: { multipartFormData in

            for (key, value) in parameters {
                if let data = (value as! String).data(using: .utf8) {
                    multipartFormData.append(data, withName: key)
                }
            }

            let imageData = image?.jpegData(compressionQuality: 0.5)

            multipartFormData.append(imageData!, withName: "profile_image", fileName: "profileImage", mimeType: "image/jpeg")

        }, to: YourUrl, headers: YourHeaders, encodingCompletion: { encodingResult in

            switch encodingResult {

            case .success(let upload, _, _):

                upload.response(completionHandler: { (defaultDataResponse) in

                    guard let httpResponse = defaultDataResponse.response else {
                        completion(nil, defaultDataResponse.error)
                        return
                    }

                    if httpResponse.statusCode == 200 {

                        do {
                            // Decode json to my model
                            let genericModel = try JSONDecoder().decode(ProfileImageModel.self, from: defaultDataResponse.data!)
                            completion(genericModel, nil)

                        } catch {

                            completion(nil, error)
                        }

                    } else {
                        completion(nil, defaultDataResponse.error)
                    }
                })

            case .failure(let encodingError):

                completion(nil, encodingError)
            }
        })

    } else {

        // Get you url
        let baseUrl = YourUrlString

        // Setup normal parameters
        // This is mine, you can use yours
        let dataString = "first_name=\(parameters["first_name"]!)&last_name=\(parameters["last_name"]!)&bio=\(parameters["bio"]!)&image_status=\(parameters["image_status"]!)&location=\(parameters["location"]!)&latitude=\(parameters["latitude"]!)&longitude=\(parameters["longitude"]!)"

        let url = URL(string: baseUrl)!     // Create url
        let session = URLSession.shared     // Create shared session instance
        var request = URLRequest(url: url)  // Create url request
        request.httpMethod = "POST"         // Set http method as POST

        // Encode parameters using utf8
        if let encodedData = dataString.data(using: .utf8) {
            request.httpBody = encodedData
        }

        // Set content type and encoding acceptance parameters in header
        request.addValue("application/x-www-form-urlencoded; charset=utf-8", forHTTPHeaderField: "Content-Type")
        request.addValue("gzip", forHTTPHeaderField: "Accept-Encoding")
        request.addValue("ios", forHTTPHeaderField: "requestfrom")

        if let authToken = UserDefaults.UserData.string(forKey: .authToken) {
            request.addValue(authToken, forHTTPHeaderField: "authtoken")
        }

        // Create Session Task
        let task = session.dataTask(with: request, completionHandler: { data, response, error in

            // Hide progress
            DispatchQueue.main.async {
                AppDelegate.shared.showProgress(showHUD: .hide, message: "")
            }

            // Check error is nil
            guard error == nil else {
                completion(nil, error)
                return
            }

            // Check data not empty
            guard let data = data else {
                completion(nil, nil)
                return
            }

            do {
                // Decode JSON to my ProfileImageModel model, you can use [String: Any] or model
                let genericModel = try JSONDecoder().decode(ProfileImageModel.self, from: data)
                completion(genericModel, nil)

            } catch {

                completion(nil, error)
            }
        })
        task.resume()
    }
}

I hope this will help you.