質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

88.59%

テキストと写真のPOSTについて

受付中

回答 0

投稿

  • 評価
  • クリップ 0
  • VIEW 404

xinxin

score 16

初心者です。
POSTを使ってカメラロールから選んだ写真とRealmに入っている文字データを一緒にPHPにPOSTしたいです。まず、POSTClassを書きました。

import UIKit
class POSTClass {
    var restext: String
    var responsestatus: String
    var isFinished: Bool
    init() {
        self.restext = ""
        self.responsestatus = ""
        self.isFinished = false
    }

    @objc
    func multipartPost(urlString: String, parameters: [String: Any]) {

        let url = URL(string: urlString)
        var request = URLRequest(url: url!)
        request.httpMethod = "POST"

        let (headers, body) = POSTClass.createMultiPartPost(parameters: parameters)

        // ヘッダーの設定
        for header in headers {
            request.addValue(header.value, forHTTPHeaderField: header.key)
        }

        // Bodyの設定
        request.httpBody = body
        self.isFinished = false
        let task = URLSession.shared.dataTask(with: request) { data, response, error in
            if let data = data, let response = response {
                if let error = error{
                    self.responsestatus="ERROR"
                }
                else{
                    self.responsestatus="OK"
                }
                self.restext = String(data: data, encoding: String.Encoding(rawValue: String.Encoding.utf8.rawValue))!
                /*
                do {
                    let json = try JSONSerialization.jsonObject(with: data, options: JSONSerialization.ReadingOptions.allowFragments)
                    print(json)
                } catch {
                    print("parse error")
                }
                */
                self.isFinished = true
            } else {
                self.responsestatus="ERROR"
                self.isFinished = true
            }
        }

        task.resume()  
    }

    static func createMultiPartPost(parameters: [String: Any]) -> (headers: [String:String], body: Data) {

        let uniqueId = UUID().uuidString
        let boundary = "---------------------------\(uniqueId)"

        let header = [
            "Content-Type" : "multipart/form-data; boundary=\(boundary)"
        ]

        var body = Data()

        let boundaryText = "--\(boundary)\r\n"


        for param in parameters {

            switch param.value {
            case let image as UIImage:

                let imageData = image.jpegData(compressionQuality: 0.75)
                body.append(boundaryText.data(using: .utf8)!)
                body.append("Content-Disposition: form-data; name=\"\(param.key)\"; filename=\"\(uniqueId).jpg\"\r\n".data(using: .utf8)!)
                body.append("Content-Type: image/jpeg\r\n\r\n".data(using: .utf8)!)

                body.append(imageData!)
                body.append("\r\n".data(using: .utf8)!)

            case let string as String:

                body.append(boundaryText.data(using: .utf8)!)
                body.append("Content-Disposition: form-data; name=\"\(param.key)\"\r\n\r\n".data(using: .utf8)!)
                body.append(string.data(using: .utf8)!)
                body.append("\r\n".data(using: .utf8)!)

            case let value as Any:

                body.append(boundaryText.data(using: .utf8)!)

                body.append("Content-Disposition: form-data; name=\"\(param.key)\"\r\n\r\n".data(using: .utf8)!)
                body.append(String(describing: value).data(using: .utf8)!)
                body.append("\r\n".data(using: .utf8)!)

            default:
                break
            }
        }   
        body.append("--\(boundary)--\r\n".data(using: .utf8)!)

        return (header, body)
    }
}


一回別のViewControllerで同じように写真をPOSTしています。
そこではレスポンスとしてclient.restextがかえって来てそれをRealmの中に入れています。下のようなコードです。この場合はきちんとPOST&Realm出来ていました。

@objc func submit() {
        self.activity.startAnimating()
        let client = POSTClass()
        DispatchQueue.global(qos: .default).async {
            // 非同期処理などを実行
            let parameters:[String: Any]  = ["file": self.uiImage]
            client.multipartPost(urlString: "https://***.php", parameters: parameters)
            //戻り値は
            while(client.isFinished == false){
                //待つ
                Thread.sleep(forTimeInterval: 0.5)
            }
            // 非同期処理などが終了したらメインスレッドでアニメーション終了
            DispatchQueue.main.async {
                // アニメーション終了
                self.activity.stopAnimating()
                print(client.restext)
                print(client.responsestatus)
            }
            //Realmのインスタンス取得
            do {
                let realm = try Realm()
                let person = [realmDataSet(value: ["userID": client.restext])]
                try! realm.write {
                    realm.add(person)
                    let person = try! realm.objects(realmDataSet.self)
                    print("person:", person.description)
                }
            } catch{
                print("error")
            }
        }


下のコードは、RealmのClassです。

import RealmSwift

public class realmDataSet: Object {
    @objc public dynamic var userID = ""
}


実際に写真とRealmの中の文字列をPOSTをするViewControllerでこのようなコードを書きました。

import UIKit
import RealmSwift

class CheckViewController: UIViewController,UIImagePickerControllerDelegate, UINavigationControllerDelegate {

    var uiImage: UIImage?

    @IBOutlet weak var image4View: UIImageView!
    @IBOutlet weak var submitButton: UIButton!
    @IBOutlet weak var activity: UIActivityIndicatorView!
    let realm = try! Realm()
    override func viewDidLoad() {
        super.viewDidLoad()
        image4View.image = uiImage
        image4View.contentMode = UIView.ContentMode.scaleAspectFit
        // Do any additional setup after loading the view.
        // 送信ボタン
        submitButton.addTarget(self, action: #selector(self.submit), for: .touchUpInside)
        self.view.addSubview(submitButton)
        self.activity.hidesWhenStopped=true
        self.activity.style = UIActivityIndicatorView.Style.whiteLarge
    }
    // POST送信
    @objc func submit() {
        self.activity.startAnimating()
        let person = try! realm.objects(realmDataSet.self)
        let client = POSTClass()

        print("person:", person.description)
        // Realmに保存されているrealmDataSet型のobjectsを取得。
        let myUserID = person[0].userID
        DispatchQueue.global(qos: .default).async {
            // 非同期処理などを実行
            let parameters:[String: Any]  = ["userID": myUserID ,"file": self.uiImage]
        client.multipartPost(urlString: "https://***.php", parameters: parameters)
            //戻り値は
            while(client.isFinished == false){
            //待つ
            Thread.sleep(forTimeInterval: 0.5)
        }

        // 非同期処理などが終了したらメインスレッドでアニメーション終了
        DispatchQueue.main.async {
            // アニメーション終了
            self.activity.stopAnimating()
            print(client.responsestatus)
            if client.responsestatus == "OK"{
                let alertController = UIAlertController(
                    title : nil,
                    message : "送信が完了しました。",
                    preferredStyle : .alert)
                alertController.addAction(
                    UIAlertAction(title: "OK", style: .default, handler: nil)
                )
                self.present(alertController,animated: true, completion: nil)
            }else{
                let alertController = UIAlertController(
                    title : nil,
                    message : "送信に失敗しました。",
                    preferredStyle : .alert)
                alertController.addAction(
                    UIAlertAction(title: "OK", style: .default, handler: nil)
                )
                self.present(alertController,animated: true, completion: nil)
            }
        }
    }
}
}


コードにエラーはないんですが、実行をし、ボタンを押したら実機ではself.activity.startAnimating()が始まり、しばらくした後にPOSTClassの方のBodyの設定のところの
self.restext = String(data: data, encoding: String.Encoding(rawValue: String.Encoding.utf8.rawValue))!
というところで Fatal error: Unexpectedly found nil while unwrapping an Optional value と出て来てしまいました。
どこが間違っているのでしょうか?
ご教授お願いします。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正の依頼

  • fuzzball

    2019/01/10 09:41

    質問内容は、RealmにもPOSTにも関係ないように見えますが。

    キャンセル

  • fuzzball

    2019/01/10 10:00

    これ以上自分で調べられることは無いと思っていますか?

    キャンセル

  • fuzzball

    2019/01/10 10:26

    String.Encoding(rawValue: String.Encoding.utf8.rawValue)
    これ何やってるのか理解してます?

    キャンセル

まだ回答がついていません

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 88.59%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る