Saltar al contenido

Subir imagen con parámetros en Swift

Te damos la bienvenida a nuestro espacio, aquí encontrarás la resolución a lo que buscabas.

Solución:

En su comentario a continuación, nos informa que está utilizando el $_FILES sintaxis para recuperar los archivos. Eso significa que desea crear un multipart/form-data solicitud. El proceso es básicamente:

  1. Especifique un límite para su multipart/form-data solicitud.

  2. Especifique un Content-Type de la solicitud que especifica que multipart/form-data y cuál es el límite.

  3. Cree el cuerpo de la solicitud, separando los componentes individuales (cada uno de los valores publicados, así como entre cada carga).

Para obtener más detalles, consulte RFC 7578. De todos modos, en Swift 3 y versiones posteriores, esto podría verse así:

/// Create request
///
/// - parameter userid:   The userid to be passed to web service
/// - parameter password: The password to be passed to web service
/// - parameter email:    The email address to be passed to web service
///
/// - returns:            The `URLRequest` that was created

func createRequest(userid: String, password: String, email: String) throws -> URLRequest 
    let parameters = [
        "user_id"  : userid,
        "email"    : email,
        "password" : password]  // build your dictionary however appropriate

    let boundary = generateBoundaryString()

    let url = URL(string: "https://example.com/imageupload.php")!
    var request = URLRequest(url: url)
    request.httpMethod = "POST"
    request.setValue("multipart/form-data; boundary=(boundary)", forHTTPHeaderField: "Content-Type")

    let fileURL = Bundle.main.url(forResource: "image1", withExtension: "png")!
    request.httpBody = try createBody(with: parameters, filePathKey: "file", urls: [fileURL], boundary: boundary)

    return request


/// Create body of the `multipart/form-data` request
///
/// - parameter parameters:   The optional dictionary containing keys and values to be passed to web service.
/// - parameter filePathKey:  The optional field name to be used when uploading files. If you supply paths, you must supply filePathKey, too.
/// - parameter urls:         The optional array of file URLs of the files to be uploaded.
/// - parameter boundary:     The `multipart/form-data` boundary.
///
/// - returns:                The `Data` of the body of the request.

private func createBody(with parameters: [String: String]?, filePathKey: String, urls: [URL], boundary: String) throws -> Data 
    var body = Data()

    parameters?.forEach  (key, value) in
        body.append("--(boundary)rn")
        body.append("Content-Disposition: form-data; name="(key)"rnrn")
        body.append("(value)rn")
    

    for url in urls 
        let filename = url.lastPathComponent
        let data = try Data(contentsOf: url)
        let mimetype = mimeType(for: filename)

        body.append("--(boundary)rn")
        body.append("Content-Disposition: form-data; name="(filePathKey)"; filename="(filename)"rn")
        body.append("Content-Type: (mimetype)rnrn")
        body.append(data)
        body.append("rn")
    

    body.append("--(boundary)--rn")
    return body


/// Create boundary string for multipart/form-data request
///
/// - returns:            The boundary string that consists of "Boundary-" followed by a UUID string.

private func generateBoundaryString() -> String 
    return "Boundary-(UUID().uuidString)"


/// Determine mime type on the basis of extension of a file.
///
/// This requires `import MobileCoreServices`.
///
/// - parameter path:         The path of the file for which we are going to determine the mime type.
///
/// - returns:                Returns the mime type if successful. Returns `application/octet-stream` if unable to determine mime type.

private func mimeType(for path: String) -> String 
    let pathExtension = URL(fileURLWithPath: path).pathExtension as NSString

    guard
        let uti = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, pathExtension, nil)?.takeRetainedValue(),
        let mimetype = UTTypeCopyPreferredTagWithClass(uti, kUTTagClassMIMEType)?.takeRetainedValue()
    else 
        return "application/octet-stream"
    

    return mimetype as String

Con:

extension Data 

    /// Append string to Data
    ///
    /// Rather than littering my code with calls to `data(using: .utf8)` to convert `String` values to `Data`, this wraps it in a nice convenient little extension to Data. This defaults to converting using UTF-8.
    ///
    /// - parameter string:       The string to be added to the `Data`.

    mutating func append(_ string: String, using encoding: String.Encoding = .utf8) 
        if let data = string.data(using: encoding) 
            append(data)
        
    

Teniendo todo esto, ahora debe enviar esta solicitud. Aconsejaría que esto se haga de forma asincrónica. Por ejemplo, usando URLSession, harías algo como:

let request: URLRequest

do 
    request = try createRequest(userid: userid, password: password, email: email)
 catch 
    print(error)
    return


let task = URLSession.shared.dataTask(with: request)  data, response, error in
    guard let data = data, error == nil else 
        // handle error here
        print(error ?? "Unknown error")
        return
    

    // parse `data` here, then parse it

    // note, if you want to update the UI, make sure to dispatch that to the main queue, e.g.:
    //
    // DispatchQueue.main.async 
    //     // update your UI and model objects here
    // 

task.resume()

Para las representaciones de Swift 2, consulte la revisión anterior de esta respuesta.

AlamoFire ahora es compatible con Multipart:

https://github.com/Alamofire/Alamofire#uploading-multipartformdata

Aquí hay una publicación de blog con un proyecto de muestra que trata sobre el uso de Multipart con AlamoFire.

http://www.thorntech.com/2015/07/4-essential-swift-networking-tools-for-working-with-rest-apis/

El código relevante podría verse así (asumiendo que está usando AlamoFire y SwiftyJSON):

func createMultipart(image: UIImage, callback: Bool -> Void)
    // use SwiftyJSON to convert a dictionary to JSON
    var parameterJSON = JSON([
        "id_user": "test"
    ])
    // JSON stringify
    let parameterString = parameterJSON.rawString(encoding: NSUTF8StringEncoding, options: nil)
    let jsonParameterData = parameterString!.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: true)
    // convert image to binary
    let imageData = UIImageJPEGRepresentation(image, 0.7)
    // upload is part of AlamoFire
    upload(
        .POST,
        URLString: "http://httpbin.org/post",
        multipartFormData:  multipartFormData in
            // fileData: puts it in "files"
            multipartFormData.appendBodyPart(fileData: jsonParameterData!, name: "goesIntoFile", fileName: "json.txt", mimeType: "application/json")
            multipartFormData.appendBodyPart(fileData: imageData, name: "file", fileName: "iosFile.jpg", mimeType: "image/jpg")
            // data: puts it in "form"
            multipartFormData.appendBodyPart(data: jsonParameterData!, name: "goesIntoForm")
        ,
        encodingCompletion:  encodingResult in
            switch encodingResult 
            case .Success(let upload, _, _):
                upload.responseJSON  request, response, data, error in
                    let json = JSON(data!)
                    println("json:: (json)")
                    callback(true)
                
            case .Failure(let encodingError):
                callback(false)
            
        
    )


let fotoImage = UIImage(named: "foto")
    createMultipart(fotoImage!, callback:  success in
    if success  
)

Reseñas y valoraciones del artículo

Más adelante puedes encontrar las explicaciones de otros programadores, tú además eres capaz mostrar el tuyo si lo crees conveniente.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *