プロフィール画像をサーバーにアップロードしようとしています。私はJSON Serialization
をやっている間にエラーが発生しました。JSONシリアル化中にエラーが発生しました。データが正しい形式ではありません
ログにエラーメッセージがある:不明なタイプの画像フォーマットを作成
[一般]エラーある、
データがので読み取ることができませんでし正しい形式ではありません
画像はフォトライブラリから画像を選択した後に表示されますが、画像がサーバーに正常にアップロードされていないため、 JSONのシリアル化中にエラーが発生しました。しかし、私はjpeg形式で画像をアップロードしようとしているので、正しい形式ではないと言われている理由はわかりません。
ここでは簡略化したコードです。何が悪かったのか? :(サーバから返さ
import UIKit
class HomepageVC: UIViewController, UINavigationControllerDelegate, UIImagePickerControllerDelegate {
@IBAction func editProfilePictureButtonDidPressed(_ sender: Any) {
// users choose photo from library or camera
let imagePickerController = UIImagePickerController()
imagePickerController.delegate = self
imagePickerController.allowsEditing = true
let actionSheet = UIAlertController(title: "Photo Source", message: "please choose your source", preferredStyle: .actionSheet)
// action camera
let actionCamera = UIAlertAction(title: "Camera", style: .default) { (action) in
if UIImagePickerController.isSourceTypeAvailable(.camera) {
imagePickerController.sourceType = .camera
self.present(imagePickerController, animated: true, completion: nil)
} else {
self.showAlert(alertTitle: "Opppss", alertMessage: "camera can't be used/not available", actionTitle: "OK")
print("camera can't be used/not available")
}
}
// action photo library
let actionPhotoLibrary = UIAlertAction(title: "Photo Library", style: .default) { (action) in
imagePickerController.sourceType = .photoLibrary
self.present(imagePickerController, animated: true, completion: nil)
}
//action cancel
let actionCancel = UIAlertAction(title: "Cancel", style: .cancel, handler: nil)
actionSheet.addAction(actionCamera)
actionSheet.addAction(actionPhotoLibrary)
actionSheet.addAction(actionCancel)
self.present(actionSheet, animated: true, completion: nil)
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
let image = info[UIImagePickerControllerOriginalImage] as! UIImage
avatarImage.image = image
picker.dismiss(animated: true, completion: nil)
// call func of uploading file to PHP server
uploadAvatar()
}
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
picker.dismiss(animated: true, completion: nil)
}
// custom HTTP request body to upload image file
func createBodyWithParams(_ parameters: [String: String]?, filePathKey: String?, imageDataKey: Data, boundary: String) -> Data {
var body = Data();
if parameters != nil {
for (key, value) in parameters! {
body.appendString("--\(boundary)\r\n")
body.appendString("Content-Disposition: form-data; name=\"\(key)\"\r\n\r\n")
body.appendString("\(value)\r\n")
}
}
// kita set agar image yang di upload kemudian berformat .jpg
let filename = "avatar.jpg"
let mimetype = "image/jpg"
body.appendString("--\(boundary)\r\n")
body.appendString("Content-Disposition: form-data; name=\"\(filePathKey!)\"; filename=\"\(filename)\"\r\n")
body.appendString("Content-Type: \(mimetype)\r\n\r\n")
body.append(imageDataKey)
body.appendString("\r\n")
body.appendString("--\(boundary)--\r\n")
return body as Data
}
// uploading image to server
func uploadAvatar() {
// get ID from Default variable
let id = userInfo!["id"] as! String
let url = URL(string: "http://localhost/Twitter/uploadAvatar.php")!
var request = URLRequest(url: url)
request.httpMethod = "POST"
let param = ["id" : id]
let boundary = "Boundary-\(UUID().uuidString)"
request.setValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")
let imageData = UIImageJPEGRepresentation(avatarImage.image!, 0.5)
// if not compressed, return ... do not continue to code
if imageData == nil {
return
}
// constructing http body
request.httpBody = createBodyWithParams(param, filePathKey: "file", imageDataKey: imageData!, boundary: boundary)
// launc session
URLSession.shared.dataTask(with: request) { data, response, error in
DispatchQueue.main.async(execute: {
if error == nil {
// if error is nil, then show message from server
do {
// json containes $returnArray from php
let json = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as? NSDictionary
// declare new parseJSON to store json
guard let parsedJSON = json else {
print("Error while parsing")
return
}
// get id from $returnArray["id"] in PHP - parseJSON["id"]
let id = parsedJSON["id"]
// successfully uploaded
if id != nil {
// save user information from Server
UserDefaults.standard.set(parsedJSON, forKey: "parsedJSON")
// if no ID from server then show the message from server
} else {
// get main queue to communicate back to user
DispatchQueue.main.async(execute: {
let message = parsedJSON["message"] as! String
self.showAlert(alertTitle: "opppps", alertMessage: message, actionTitle: "OK")
})
}
// error doing JSON serialization
} catch {
// get main queue to communicate back to user
DispatchQueue.main.async(execute: {
let message = error.localizedDescription
self.showAlert(alertTitle: "Sorry", alertMessage: message, actionTitle: "OK")
})
}
// error ketika koneksi ke server
} else {
// get main queue to communicate back to user
DispatchQueue.main.async(execute: {
let message = error!.localizedDescription
self.showAlert(alertTitle: "oppps", alertMessage: message, actionTitle: "OK")
})
}
})
}.resume()
}
}
// extend data
extension Data {
mutating func appendString(_ string : String) {
let data = string.data(using: String.Encoding.utf8, allowLossyConversion: true)
append(data!)
}
}