6 분 소요

🤛🏻 [3주차]

1월 18일 저녁 10시 잭잭이 탈주했다.

정확한 이유도 듣지 못한 채(두루뭉술하게 백엔드 분야를 배울 기회가 왔다고 했다) 잭잭이 만든 그동안의 작업물도 전부 리셋된 후였다.

내 데스노트에 이름이 아직까지 적혀있다.

사실 이렇게 탈주 의사를 보이는 팀원들을 잘 조율하는 것도 PM의 역량이라고 생각한다.

하지만 난 의지도 책임감도 갖지 않은 팀원을 끝까지 끌고 갈 그 에너지를 다른 팀원들에게 더 나누어 주고 싶었기에, 그저 붙잡지 않고 과감하게 결단을 내렸다.

덕분에 잭잭에 나에게 전화를 건 그 새벽, 밤을 새서 잭잭이 날려먹은 화면을 처음부터 제작했다.

그나마 다행인 점은, 내 방식대로 화면을 구성해서 [목표] 화면이 더 깔끔해졌고 이제야 전체 화면들을 연결할 수 있었다는 점이었다.

3-1

아, 중간에 물론 문제가 생기긴 했다.

무슨일인지 tab bar controller에 연결한 뷰 컨트롤러에서 navigation item이 나타나지 않는 문제가 발생한 것이다(navigation controller는 화면 제일 앞에 위치하고 있었다)

이때 천재 피치가 해결책을 내놓았는데, view controller를 그 화면 바로 앞에 집어넣어 해결했다.

(아마도 기존 navigation controller와 화면 상의 간격이 너무 벌어져서 그런 문제가 생긴 것이 아닐까 생각한다.)

이걸 git organization의 새로운 브랜치인 staging에 push 했는데(피치가)

이걸 기존의 fork한 내 레포에 어떻게 불러올 수 있는지 몰랐다(내 레포에는 main 브랜치 밖에 없으니까…)

그래서 새로 배운

re-fork 하는 방법

git remote add upstream [기존 레포 url]
// 오리지널 레포를 upstream으로 추가

git remote -v
// 잘 되었는지 확인

git fetch [신규 브랜치 이름]
// 새로운 브랜치들을 이런 식으로 가져옴

git checkout staging

git push origin staging
// 내 레포에도 반영

다만 이렇게 했더니, 기존 Local 파일의 main이 작동하지 않고

line 604: starttag: invalid element name

이런 요상한 에러가 발생했다

구글링을 통해 xml 파일에 문제가 생긴 건 알겠지만, 정확한 문제 해결 방식을 몰라서

그냥 로컬에서 새로 clone을 받아왔더니 제대로 동작하기 시작했다.

[swift 서버 통신]

다음주 즈음에 서버팀이 API를 완성하기로 해서 슬슬 ios 서버 통신 방법을 정리해 보려고 한다.

사실 오늘(1월 19일 목) iOS 회의에서 통신 방법을 정리하기로 해서 미리 알아보는 것이다.

openAPI 주소에 POST로 데이터를 넘겨야 하는 상황.

HTTP BODY로 다음의 데이터를 넘겨야 한다고 하자

{
id: "dbswlsdyd",
name: "윤진용",
email: "dbswlsdyd730@naver.com",
userID:"진용01",
password: "1234",
agree: TRUE
}

이를 위해서 doby 인자 형태에 맞는 codable struct를 만들어주어야 한다.

import Foundation

struct PostComment: Codable {
    let id: String
    let name: String
    let email: String
    let userID: String
    let password: String
    let agree: Boolean

    enum CodingKeys: String, Boolean, CodingKey {
        case id, name, email, password
        case agree
        case userID = "userID"
    }
}

struct를 전부 만들었다면, post 수행 코드를 작성한다

post 코드를 작성할 때엔 먼저 post 할 body 부분을 먼저 작성하고,

그 body를 JSONEncoder()로 encode 시킨 뒤

URLSession.uploadTask(with: request, from: encodedBody)로 장식한다

func postComment(id: String, name: String, email: String, userID: String, password: String, agree: Boolean) {

    // 넣는 순서도 순서대로여야 하는 것 같다.
    let comment = PostComment(id: String, name: String, email: String, userID: String, password: String, agree: Boolean)
    guard let uploadData = try? JSONEncoder().encode(comment)
    else {return}

    // URL 객체 정의
    let url = URL(string: "https://www.notion.so/8ab9ec8ec27148c9ba1801979f75fdce")

    // URLRequest 객체를 정의
    var request = URLRequest(url: url!)
    request.httpMethod = "POST"
    // HTTP 메시지 헤더
    request.setValue("application/json", forHTTPHeaderField: "Content-Type")

    // URLSession 객체를 통해 전송, 응답값 처리
    let task = URLSession.shared.uploadTask(with: request, from: uploadData) { (data, response, error) in

        // 서버가 응답이 없거나 통신이 실패
        if let e = error {
            NSLog("An error has occured: \(e.localizedDescription)")
            return
        }
        // 응답 처리 로직
        print("comment post success")
    }
    // POST 전송
    task.resume()
}

각 명세서에 맞는 HTTP 메소드 방식으로 request 해야 하는데

3-2

Patch와 Delete를 어떻게 작성할 지 벌써부터 두렵다 ㄷㄷㄷ

그리고 우리는 로그인 방식을 X_ACCESS_TOKEN을 이용하기로 해서

헤더에 어떻게 추가해야 할지 몰라, 한참을 헤매었는데(도와주세요 구글 교수님)

import Cocoa

let session: URLSession = URLSession.shared
func session_check(url: URL, accessToken: String, completionHandler: @escaping (Data?, URLResponse?, Error?) -> Void) throws {
    var request: URLRequest = URLRequest(url: url)
    request.httpMethod = "GET"
    request.addValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
    request.addValue("Bearer " + accessToken, forHTTPHeaderField: "Authorization")
    request.addValue("Mozilla/5.0", forHTTPHeaderField: "User-Agent")
        session.dataTask(with: request, completionHandler: completionHandler).resume()
}

let accessToken: String = "xxxx-yyyy-zzzz"
let url: URL = URL(string: "http://192.168.0.26:8080/et")!
do {
    try session_check(url: url, accessToken: accessToken, completionHandler: { data, response, error in
        if let httpResponse = response as? HTTPURLResponse {
            let returnCode = httpResponse.statusCode
            if returnCode == 200 {    print("200 OK")    }
        }
    })
} catch {
    print(error)
}
sleep(1)

마침내 구글 교수님께서 한 예제를 보여주시며 의문을 해소해주셨다.

헤더에다 addValue로 accessToken을 추가해주면 되는구나…이렇게 하는거구만…

결국 GET POST PATCH DELETE 메소드들을 직접 적어보며

서버 통신의 고오수가 되어버렸다.

이번 방학 때 Spring 공부가 중점이었던 것 같은데, 어느샌가 IOS 공부를 더 많이 하고 있는 것 같다.

역시 큰 프로젝트는 사람을 억지로 성장시키는 것 같다.

func postGoal() {
        
        // 넣는 순서도 순서대로여야 하는 것 같다.
        let goal = Goal(goal_amount: Int(GoalPriceTextField.text ?? "0")!, init_amount: Int(InitPriceTextField.text ?? "0")!, category_name: GoalTextField.text ?? "디폴트 골", date: Date().toString())
        
        //print(goal)
        /*Goal(userIdx: 1, init_amount: Int(InitPriceTextField.text ?? "0")!, goal_amount: Int(GoalPriceTextField.text ?? "0")!, GoalName: GoalTextField.text ?? "디폴트 골", GoalImage: imagebase64 ?? "디폴트이미지")*/
        guard let uploadData = try? JSONEncoder().encode(goal)
        else {return}
        
        // URL 객체 정의
        let userIdx = UserDefaults.standard.integer(forKey: "userIdx")
        let url = URL(string: "https://www.pigmoney.xyz/goal/createGoal/\(userIdx)")
        
        // URLRequest 객체를 정의
        var request = URLRequest(url: url!)
        request.httpMethod = "POST"
        // HTTP 메시지 헤더
        request.setValue("application/json", forHTTPHeaderField: "Content-Type")
        request.addValue(UserDefaults.standard.string(forKey: "accessToken") ?? "0", forHTTPHeaderField: "X-ACCESS-TOKEN")
        
        request.httpBody = uploadData
        //print(String(data: uploadData, encoding: .utf8)!)
        
        // URLSession 객체를 통해 전송, 응답값 처리
        let task = URLSession.shared.uploadTask(with: request, from: uploadData) { (data, response, error) in
            
            // 서버가 응답이 없거나 통신이 실패
            if let e = error {
                NSLog("An error has occured: \(e.localizedDescription)")
                return
            }
            // 응답 처리 로직
            guard let data = data else { return }
            
            // data
            let decoder = JSONDecoder()
            if let json = try? decoder.decode(responseP.self, from: data) {
                print(json.message)
            }
        }
            // POST 전송
            task.resume()
        
    }

func patchGoal() {
            // 넣는 순서도 순서대로여야 하는 것 같다.
            /*print("\n\n\n\n\n\n")
            print("여기 꼭 확인해라 좋은 말 할 때")
            print(oldImage == self.convertImageToBase64(image: ImgUI.currentImage!))
            print(convertImageToBase64(image: ImgUI.currentImage!))
            print(GoalPriceTextField.text as Any)
            print(PriceTextField.text as Any)
            print(GoalNameTextField.text as Any)
            print("확인 끝")
            print("\n\n\n\n\n\n")*/
            
            
            let patchgoal = patchgoal(amount: Int(PriceTextField.text ?? "5") ?? 5, category_name: GoalNameTextField.text ?? "알 수 없음", image: convertImageToBase64(image: ImgUI.currentImage!), init_amount: Int(GoalPriceTextField.text ?? "5") ?? 5)
            /*let patchgoal = patchgoal(image: convertImageToBase64(image: ImgUI.currentImage!), goal_amount: Int(GoalPriceTextField.text ?? "5") ?? 5, init_amount: Int(InitPriceTextField.text ?? "5") ?? 5, category_name: GoalNameTextField.text ?? "알 수 없음")*/
            
            print("\n\n\n\n\n")
            print("=================")
            print("여기도 확인")
            print(oldImage == self.convertImageToBase64(image: ImgUI.currentImage!))
            print(patchgoal)
            print("=================")
            print("\n\n\n\n\n")
                                      
            guard let uploadData = try? JSONEncoder().encode(patchgoal) else {return}
            
            /*print("\n\n\n\n\n")
            print("=================")
            print("업로드 데이터")
            print(uploadData.self)
            print("=================")
            print("\n\n\n\n\n")*/
            
            
            // URL 객체 정의
            let userIdx = UserDefaults.standard.integer(forKey: "userIdx")
            let url = URL(string: "https://www.pigmoney.xyz/goal/modifyGoal/\(goalIdx!)/\(userIdx)")

            
            // URLRequest 객체를 정의
            var request = URLRequest(url: url!)
            request.httpMethod = "PATCH"
            // HTTP 메시지 헤더
            request.setValue("application/json", forHTTPHeaderField: "Content-Type")
            request.setValue( UserDefaults.standard.string(forKey: "accessToken") ?? "0", forHTTPHeaderField: "X-ACCESS-TOKEN")
            
            request.httpBody = uploadData
          /*  print("###############업로드 데이터다###################")
            print(String(data: uploadData, encoding: .utf8)!)*/
    
                    // URLSession 객체를 통해 전송, 응답값 처리
                    URLSession.shared.uploadTask(with: request, from: uploadData) { (data, response, error) in
                        
                        guard let data = data else {
                            print("Error: Did not receive data")
                            return
                        }
                        
                        /*print("**************응답데이터*****************")
                        print(String(data: data, encoding: .utf8)!)
                        print("**************응답데이터*****************")*/
                        
                        guard let response = response as? HTTPURLResponse, (200 ..< 299) ~= response.statusCode else {
                            print("Error: HTTP request failed")
                            return
                        }
                        
                        let decoder = JSONDecoder()
                        if let json = try? decoder.decode(goalpatchresponse.self, from: data) {
                            print(json.message)
                            
                        }
                        // POST 전송
                    }.resume()
               
        }

func loadcategory(){
        let userIdx = UserDefaults.standard.integer(forKey: "userIdx")
        if let url = URL(string: "https://www.pigmoney.xyz/category/\(userIdx)/\(flag!)"){
            
            var request = URLRequest.init(url: url)
            
            request.httpMethod = "GET"
            
            request.setValue("application/json", forHTTPHeaderField: "Content-Type")
            request.addValue( UserDefaults.standard.string(forKey: "accessToken") ?? "0", forHTTPHeaderField: "X-ACCESS-TOKEN")
            
            DispatchQueue.global().async {
                do {
                    
                    URLSession.shared.dataTask(with: request){ [self] (data, response, error) in
                        
                        guard let data = data else {
                                                  print("Error: Did not receive data")
                                                  return
                                              }
                                              
                                             // print(String(data: data, encoding: .utf8)!)
                                              
                                              
                                              
                                              guard let response = response as? HTTPURLResponse, (200 ..< 299) ~= response.statusCode else {
                                                  print("Error: HTTP request failed")
                                                  return
                                              }

                        
                        let decoder = JSONDecoder()
                        if let json = try? decoder.decode(categoryresult.self, from: data) {
                            self.resultlist =  json.result
                            observeresultlist()
                        }
                        
                    }.resume() //URLSession - end
                    
                }
            }
            
        }
        
    }  //더 있지만...이만 생략

댓글남기기