๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
๐ŸŽ iOS

[SwiftUI 3.0] URLSession ๊ณผ List, @Published, @ObservedObject ์‚ฌ์šฉํ•˜๊ธฐ

by ํ‹ด๋”” 2021. 10. 27.
728x90
๋ฐ˜์‘ํ˜•

SwiftUI ์—์„œ๋Š” ๋ทฐ์—์„œ ์‚ฌ์šฉํ•  ๊ฐ’์„ ์ €์žฅํ•˜๋Š” ๋ฐฉ์‹์ด ๊ธฐ์กด Storyboard ๋ฐฉ์‹๊ณผ๋Š” ๋‹ค๋ฆ…๋‹ˆ๋‹ค.

์˜ค๋Š˜์€ ๋ทฐ ๋ฐ–์˜ ํด๋ž˜์Šค์—์„œ ์‚ฌ์šฉ๊ฐ€๋Šฅํ•œ 

ํ”„๋กœํผํ‹ฐ์›Œ๋ ˆํผ ์ธ @ObservedObject๋ฅผ ์†Œ๊ฐœํ•˜๊ณ 

์•„์ฃผ ๊ฐ„๋‹จํ•œ ํŠœํ† ๋ฆฌ์–ผ๋กœ

์‚ฌ์šฉ๋ฒ•์„ ์ •๋ฆฌํ•˜๋ ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค


@ObservedObject๋ฅผ ์•Œ๊ธฐ ์ „์— ObservableObject์— ๋Œ€ํ•ด์„œ ์•Œ์•„๋ณผ๊ฒŒ์š”

ObservableObject๋Š” Combine์— ์†ํ•œ ํ”„๋กœํ† ์ฝœ์ž…๋‹ˆ๋‹ค

ํ•ด๋‹น ํฌ์ŠคํŒ…์—์„œ Combine์„ ๋‹ค๋ฃจ์ง€ ์•Š์ง€๋งŒ RxSwift์˜ ๊ธฐ๋Šฅ์ด๋ผ๊ณ  ์ƒ๊ฐํ•˜์‹œ๋ฉด ๋˜์š”

 

@ObservedObject๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด์„œ

ObservableObject ํ”„๋กœํ† ์ฝœ์„ ์ฑ„ํƒํ•ด ์ฃผ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

 

@ObservedObject๋Š” ํ•ด๋‹น ํ”„๋กœํผํ‹ฐ์˜ ๊ฐ’์ด ๋ณ€๊ฒฝ๋˜๋ฉด

@Published ํ”„๋กœํผํ‹ฐ ์›Œ๋ ˆํผ๊ฐ€ ์ž๋™์œผ๋กœ ๊ฐ’์˜ ๋ณ€๊ฒฝ์„ ์•Œ๋ ค์ฃผ๊ณ  

์—…๋ฐ์ดํŠธ๊ฐ€ ํ•„์š”ํ•œ ๋ถ€๋ถ„์˜ UI๋ฅผ ๊ทธ๋ฆฌ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค!

 

์šฐ์„  api๋ฅผ ํ†ต์‹ ํ•˜๋ฉด ๋ฐ›๊ฒŒ ๋˜๋Š” JSON ๊ตฌ์กฐ๋ฅผ struct๋กœ ์ƒ์„ฑํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค

BoardList.swift

struct Struct: Decodable {
    var data: [Board]?
}

struct Board: Decodable {
    var idx: String?
    var title: String?
    var register_date: String?
}

์ œ๊ฐ€ ์‚ฌ์šฉํ•œ api๋Š” ๋”•์…”๋„ˆ๋ฆฌ ๊ตฌ์กฐ์— data๋ผ๋Š” ํ‚ค๊ฐ’์œผ๋กœ Board๋ฅผ ๋ฆฌ์ŠคํŠธ ํ˜•ํƒœ๋กœ ๊ฐ€์ง€๊ณ  ์žˆ์–ด์š”

๊ฐ’์ด ์˜ฌ์ˆ˜๋„ ์žˆ๊ณ  ์•ˆ์˜ฌ์ˆ˜๋„ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์˜ต์…”๋„๋กœ ์„ค์ •ํ•ด ์ฃผ์—ˆ์–ด์š”

 

์ด ๊ตฌ์กฐ๋ฅผ ์ฐธ์กฐํ•ด์„œ ํ…Œ์ด๋ธ” ๋ทฐ(SwiftUI์—์„œ๋Š” List)์— ๋“ค์–ด๊ฐˆ ํ•œ ํ–‰์„ ๊ทธ๋ ค๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค

BoardRow.swift

import SwiftUI

struct BoardRow: View {
    var board: Board
    
    var body: some View {
        VStack {
            Text(board.title ?? "title is null")
                .foregroundColor(.blue)
                .lineLimit(nil)
            
            Spacer()
            
            Text(board.register_date ?? "(๋“ฑ๋ก์ผ ์—†์Œ)")
                .foregroundColor(.green)
                .lineLimit(nil)
        }
    }
}

์•„์ง UI๋ฅผ ๊ทธ๋ฆฌ๋Š” ๊ฒƒ์ด ์ต์ˆ™ํ•˜์ง€ ์•Š์•„ ์—‰๋ง์ด์ง€๋งŒ

List์— ๋ณด์—ฌ์ง€๊ธฐ์— ์ถฉ๋ถ„ํ•ฉ๋‹ˆ๋‹ค

๋งŒ์•ฝ์— swift ํŒŒ์ผ์„ ์ƒ์„ฑํ•˜๊ณ  canvas์—์„œ ๋ทฐ๊ฐ€ ๋ณด์—ฌ์ง€๊ณ  ์‹ถ๋‹ค๋ฉด ์•„๋ž˜์™€ ๊ฐ™์ด 

PreviewProvider๋ฅผ ์ž‘์„ฑํ•ด ์ฃผ์‹œ๋ฉด ๋ฉ๋‹ˆ๋‹ค.

struct BoardRow_Previews: PreviewProvider {
    static var previews: some View {
        BoardRow(board: Board(idx: nil, title: nil, register_date: nil))
    }
}

 

์ด์ œ URLSession์„ ์ด์šฉํ•ด์„œ api ํ†ต์‹ ์„ ํ•˜๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค

NetworkManager.swift

import SwiftUI

// 1
class NetworkManager: ObservableObject {

	// 2
    @Published var boardList = [Board]()
    
    init() {
        guard let url = URL(string: "api ์ฃผ์†Œ ") else {
            return
        }
        
        URLSession.shared.dataTask(with: url) { data, _, _ in
            guard let data = data else {
                return
            }
            
            do {
            	// 3
                let result = try JSONDecoder().decode(Struct.self, from: data)
                // 4
                DispatchQueue.main.async {
                    self.boardList = result.data ?? [Board]()
                }
            } catch {
                print("\(error.localizedDescription)\n\(error)")
            }
            
           
        }.resume()
    }
}

2๋ฒˆ์—์„œ @Published ํ”„๋กœํผํ‹ฐ ์›Œ๋ ˆํผ๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด 

1๋ฒˆ์—์„œ ObservableObject ํ”„๋กœํ† ์ฝœ์„ ์ฑ„ํƒํ•ด ์ค๋‹ˆ๋‹ค

@Published ํ”„๋กœํผํ‹ฐ ์›Œ๋ ˆํผ๋ฅผ ์ด์šฉํ•ด์„œ ๋‹ค๋ฅธ ๋ทฐ์—์„œ ์ด ํ”„๋กœํผํ‹ฐ๋ฅผ ์‚ฌ์šฉํ•˜๊ณ 

๊ฐ’์ด ๋ณ€๊ฒฝ๋˜๋Š” ๊ฒƒ์„ ์•Œ๋ ค์ค„ ์ˆ˜ ์žˆ์–ด์š”

3 ์—์„œ ์ด์ „์— JSON ๊ตฌ์กฐ๋ฅผ sturct๋กœ ๋ณ€๊ฒฝํ•˜๊ณ  

4 ์—์„œ ํ†ต์‹  ์„ฑ๊ณตํ•œ ๋ฐ์ดํ„ฐ๋ฅผ @Published ํ”„๋กœํผํ‹ฐ ์›Œ๋ ˆํผ๋กœ ์ง€์ •๋˜์–ด ์žˆ๋Š”

boardList ํ”„๋กœํผํ‹ฐ์— ๋‹ด์•„์ค๋‹ˆ๋‹ค

 

import SwiftUI

struct ContentView: View {
	// 1
    @ObservedObject var networkManager = NetworkManager()
    
    var body: some View {
        NavigationView {
        	// 2
            List(networkManager.boardList, id: \.title) { board in
                Group {
                	// 3
                    BoardRow(board: board)
                }
                
            }
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

1์—์„œ ๋ณด์‹œ๋ฉด ObservableObject๋ฅผ ์ฑ„ํƒํ•œ NetworkManager ์ธ์Šคํ„ด์Šค๊ฐ€

@ObservedObject ํ”„๋กœํผํ‹ฐ ์›Œ๋ ˆํผ๋กœ ์ง€์ •๋˜์–ด ์žˆ๋Š” ๊ฒƒ์„ ์•Œ์ˆ˜ ์žˆ์–ด์š”

์ด์ „์— NetworkManager ์˜ ์ƒ์„ฑ์ž์—์„œ  URLSession ์„ ์ด์šฉํ•ด์„œ api ํ†ต์‹ ์„ ์ˆ˜ํ–‰ํ•˜๊ณ 

์„ฑ๊ณต์ ์œผ๋กœ  JSON ์ด struct๋กœ ๋ณ€๊ฒฝ๋˜์–ด boardList์˜ ๊ฐ’์„ ๋ณ€๊ฒฝํ•˜๋ฉด 

ContentView์—์„œ ๊ฐ’์ด ๋ณ€๊ฒฝ๋œ ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค

2์—์„œ networkManager์˜ boardList๋กœ List๋ฅผ ๊ทธ๋ ค์ฃผ๊ณ 

์…€์€ ์ด์ „์— ๋งŒ๋“ค์–ด ๋‘์—‡๋˜ BoardRow๋กœ ์ง€์ •ํ•ด ์ค๋‹ˆ๋‹ค

๋ถ€๋„๋Ÿฌ์šด UI์ด์ง€๋งŒ ๊ฒฐ๊ณผ๋ฅผ ์ฒจ๋ถ€ํ•ด ๋ด…๋‹ˆ๋‹ค..

์ด์ „์— ์ต์ˆ™ํ•˜๋˜ ์Šคํ† ๋ฆฌ๋ณด๋“œ์™€๋Š” ๋‹ฌ๋ฆฌ api ํ†ต์‹ ์ด ์„ฑ๊ณตํ•˜๋ฉด

์–ด๋–ป๊ฒŒ ํ™”๋ฉด์— ์—…๋ฐ์ดํŠธ๋ฅผ ์•Œ๋ฆฌ๊ณ  ๊ทธ๋ ค์•ผ ํ• ์ง€ ๊ฐ์ด ์•ˆ์˜ค๋”๋ผ๊ตฌ์š”

๊ทธ๋Ÿด๋• @Published์™€ @ObservedObject๋ฅผ ์‚ฌ์šฉํ•ด๋ณด์„ธ์š”

 

์ €๋„ ๋ฐฐ์šฐ๋Š” ๋‹จ๊ณ„์ด๋‹ˆ ํ‹€๋ฆฌ๊ฑฐ๋‚˜ ์ถ”๊ฐ€๋˜์–ด์•ผ ํ•  ๋ถ€๋ถ„์ด ์žˆ๋‹ค๋ฉด ๋Œ“๊ธ€๋กœ ์•Œ๋ ค์ฃผ์‹œ๋ฉด ๊ฐ์‚ฌํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค

 

728x90
๋ฐ˜์‘ํ˜•

๋Œ“๊ธ€