[iOS/Python] 서버와 데이터 주고받기(Using Alamofire & Flask)

frogKing·2022년 7월 6일
0

배경

어느덧 졸업작품이 끝을 향해 달려가고 있다. 이번에는 서버에 사용자의 전신 사진을 보내면 서버에서 해당 사진을 바탕으로 딥러닝 모듈을 돌린 뒤 반환되는 obj 파일을 사용자에게 전달하는 것을 코드로 구현하였다. 동작을 간단하게 설명해보면 다음과 같다.

  1. (앱) 서버로 이미지 전송
  2. (서버) 이미지를 딥러닝 모듈로 처리한 다음 앱으로 obj 파일 전송
  3. (앱) 해당 obj 파일을 받아서 화면에 렌더링

구현

1. 서버로 이미지 전송

  • Alamofire를 이용하여 이미지를 서버로 업로드하는 코드
  • responseJSON을 통해 얻은 결과(obj 파일을 얻는 url)를 바탕으로 3번 작업 진행
func getUserModel(_ image: UIImage, completion: @escaping () -> Void) {
        let url = K.flaskURL + "createUserModel"
        let headers: HTTPHeaders = ["Content-type": "multipart/form-data"]
        
        AF.upload(multipartFormData: { multipart in
            if let imageData = image.pngData() {
                multipart.append(imageData, withName: "file", fileName: "\(UserInfo.shared.uid!).png", mimeType: "image/png")
            }
            //            if let imageData = image.jpegData(compressionQuality: 1) {
            //                multipart.append(imageData, withName: "file", fileName: "k.jpg", mimeType: "image/jpeg")
            //            }
        },
                  to: url,
                  method: .post,
                  headers: headers).responseJSON { response in
            
            switch response.result {
            case .success:
                print("Success")
                guard let result = response.data else { return }
                do {
                    let decoder = JSONDecoder()
                    
                    let json = try decoder.decode(SceneModel.self, from: result)
                    self.getTempUserModel(url: json.url)
                    completion()
                } catch {
                    print("error!\(error)")
                }
                
            case .failure(let e):
                print(e)
            }
        }
    }

2. 이미지를 딥러닝 모듈로 처리한 다음 앱으로 obj 파일 전송

  • create_user_model : 앱으로부터 이미지를 받고 해당 이미지를 바탕으로 딥러닝 모듈로 처리한 파일을 다운로드 받을 수 있는 url을 전달
  • download_user_model : obj 파일을 전달하는 url.
@app.route('/createUserModel', methods=['POST'])
def create_user_model():
    # HTTP POST 방식으로 전송된 이미지 받기
    f = request.files['file'] # 파일 받기
    d = request.form          # 데이터 받기

    f.save("./user_images/" + secure_filename(f.filename))

    # 사용자의 사진을 바탕으로 사용자 모델 생성 및 user_models에 저장


    # 해당 파일을 반환
    json_data = {
        'url': "/downloadUserModel"
    }

    return jsonify(json_data)
    # return send_file("./user_models/" + "temp_mesh.obj", mimetype='application/wavefront-obj')


@app.route('/downloadUserModel', methods=['GET'])
def download_user_model():
    return send_file("./user_models/" + "temp_mesh.obj", mimetype='application/wavefront-obj')

3. 해당 obj 파일을 받아서 화면에 렌더링

가장 어려웠던 부분은 현재 내 프로젝트가 mvvm을 따르고 있는데(부분적으로..?) Service 쪽에서 값이 변경되었을 때 어떻게 하면 VC에서 변경된 순간에 set3DModel 함수를 불러올 수 있는지였다. 이 때 Observable을 이용하면 값이 바뀌었을 때 할 동작을 지정할 수 있다는 것을 알게 되었다. Observable에 대한 설명은 다음 포스팅에서 진행하고 우선은 obj 파일을 받아서 화면에 렌더링하는 코드를 알아보겠다.

  • 1번에 해당 코드가 있는데 이는 사용자 모델 사진을 서버에 업로드한 다음 반환된 json에서 url을 뽑아내고 이 값을 통해 Obj 파일을 가져오는 코드이다.
  • 이 때 Codable을 이용해서 SceneModel이라는 파일을 하나 생성해주어야 한다.
let decoder = JSONDecoder()
                    
let json = try decoder.decode(SceneModel.self, from: result)
self.getTempUserModel(url: json.url)
  • url을 가져와서 서버에서 obj 파일을 다운로드하는 모습.
    - 해당 obj 파일은 앱에 저장해뒀다가 가져오고 싶을 때 가져올 것이기 때문에 destinationPath를 지정하여 파일 내부에 저장.
    - userModelPath.value에 해당 url을 넣어두면 Observable을 이용하여 해당 url에 대한 처리를 함.
    func getTempUserModel(url: String) {
        let destinationPath: DownloadRequest.Destination = { _, _ in
            let documentsURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0];
            let fileURL = documentsURL.appendingPathComponent("my_mesh.obj")
            return (fileURL, [.removePreviousFile, .createIntermediateDirectories])
        }
        
        let url = K.flaskURL + url
        AF.download(url, to: destinationPath)
            .downloadProgress { progress in
            }
            .responseData { response in
                switch response.result {
                case .success:
                    print("Success")
                    // self.userModelPath.value = self.getFilePathInDocuments(fileName: "my_mesh.obj")
                    self.userModelPath.value = response.fileURL
                case .failure(let e):
                    print(e)
                }
            }
    }
profile
내가 이걸 알고 있다고 말할 수 있을까

0개의 댓글