yehey's 공부 노트 \n ο(=•ω<=)ρ⌒☆

[ios] Locord 개발일지 - 서버에 이미지, 데이터 POST 본문

개발/프로젝트

[ios] Locord 개발일지 - 서버에 이미지, 데이터 POST

yehey 2021. 3. 3. 14:42

처음에는 Alamofire를 사용하지 않고 따로 함수를 제작했었는데, 이미지 파일을 업로드하는 방법을 도저히 알아낼 수가 없었다..

Alamofire를 사용하려고 하지 않았던 이유는 이미지가 아닌 데이터와 이미지 데이터를 함께 보내고 싶었기 때문!

구글링을 통해 알아낸 Alamofire 이미지 업로드는 이미지만 업로드 하는 예시들만 확인해서 데이터는 같이 못 보낸다고 생각해서 사용하지 않았는데 사진을 꼭 업로드해야했기 때문에 데이터를 같이 업로드 하는 방법을 찾았다.

 

우선 코드는 다음과 같다! 업로드와 관련 없다고 생각되는 코드들은 생략했음! 그냥 Alamofire 이미지 업로드 방식 이해를 돕는다고 생각하면 될 듯

import UIKit
import EmojiPicker
import Alamofire
import Foundation

class recordCreateView: UIViewController {

    //MARK: - Properties
    @IBOutlet weak var dateField : DateTextfield!
    @IBOutlet weak var image: UIImageView!
    @IBOutlet weak var diarytext: UITextView!
    @IBOutlet weak var okButton: UIButton!
    @IBOutlet weak var cancelButton: UIButton!
    @IBOutlet weak var emojiButton : UIButton!
    
    //url
    let serverURL = "https://03f171ee0670.ngrok.io/memory/memories/"
    
    struct DataToPost : Codable {
        var date, emoji, content : String
    }
    
    //MARK: - Lifecycle
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        //imagePicker.delegate = self
        //self.dateField.dateChanged = {date in print(date)}
    }
    
    //MARK: - Alert
    //alert 함수
    func showAlertOkNo(msg: String){
        let alert = UIAlertController(title: nil, message: msg, preferredStyle: .alert)
        let okButton = UIAlertAction(title: "네", style: .default) { (action) in
            DiaryPost.data.uploadDiary(date: self.dateField.text!, emoji: self.emojiButton.currentTitle!, content: self.diarytext.text!, self.image.image!, url: self.serverURL)
            //↑ 데이터 POST 함수 호출 (DiaryPost 구조체에 data 객체의 uploadDiary 함수 호출)
            self.showAlert(msg: "등록 완료!")
        }
        let noButton = UIAlertAction(title: "아니오", style: .default, handler: nil)
        alert.addAction(okButton)
        alert.addAction(noButton)
        present(alert, animated: true, completion: nil)
    }
    
    //등록하기 버튼 눌렀을 때
    @IBAction func enrollPressed(_ sender: UIButton){
        showAlertOkNo(msg: "이대로 등록하시겠습니까?")
    }
    
    //MARK: - Post
    //POST 관련 DiaryPost 구조체(?)
    struct DiaryPost {
        static let data = DiaryPost()	//자동으로 객체 생성
        
        let headers: HTTPHeaders = [	
                    "Content-type": "multipart/form-data"
                ]//HTTP 헤더
        
        func uploadDiary(date: String, emoji: String, content: String, _ photo : UIImage, url: String){
            //함수 매개변수는 POST할 데이터, url
            
            let body : Parameters = [
                "date" : date,
                "emoji" : emoji,
                "content" : content,
                "user" : 2
            ]	//POST 함수로 전달할 String 데이터, 이미지 데이터는 제외하고 구성
            
            //multipart 업로드
            AF.upload(multipartFormData: { (multipart) in
                if let imageData = photo.jpegData(compressionQuality: 1) {
                    multipart.append(imageData, withName: "photo", fileName: "photo.jpg", mimeType: "image/jpeg")
                    //이미지 데이터를 POST할 데이터에 덧붙임
                }
                for (key, value) in body {
                    multipart.append("\(value)".data(using: .utf8, allowLossyConversion: false)!, withName: "\(key)")
                    //이미지 데이터 외에 같이 전달할 데이터 (여기서는 user, emoji, date, content 등)            
                }
            }, to: url	//전달할 url
            ,method: .post		//전달 방식
            ,headers: headers).responseJSON(completionHandler: { (response) in	//헤더와 응답 처리
                print(response)
                
                if let err = response.error{	//응답 에러
                    print(err)
                    return
                }
                print("success")		//응답 성공
                
                let json = response.data
                
                if (json != nil){
                    print(json)
                }
            })
            
        }
    }
}

 

  • DataToPost : Codable 속성을 가짐, 이미지를 제외하고 업로드 할 데이터들을 타입 기반으로만 묶어놓은 것

  • serverURL : 프론트와 통신할 서버의 URL

  • showAlertOkNo : Alert를 띄워주는 함수, "네" 버튼을 누르면 post 업로드 함수를 호출함

  • DiaryPost : POST 기능과 관련된 함수, 인스턴스를 묶은 것

  • headers : 헤더 선언, HTTPHeaders 속성 상속

  • uploadDiary : POST 기능을 가진 함수

  • multipart 업로드에서 UIImage 데이터를 jpeg 데이터로 변환, 압축 퀄리티도 정할 수 있음 여기서는 1

  • 변환된 jpeg 데이터를 multipart에 붙임 (붙이는 방식으로 한번에 여러개의 데이터들을 보낼 수 있음)

  • jpeg 데이터 외에도 위에서 선언한 parameters 를 key-value 쌍으로 하나씩 append 해줌

    (보낼 데이터 = jpeg데이터 + String 데이터)

  • to: 전송할 URL , method: .post, headers: 위에서 생성한 헤더

  • AF.upload(multipartFormData: ~~~, headers: headers).responseJSON(completionHandler: Json 응답을 처리)

  • error와 success를 처리

Comments