본문 바로가기

EXPERIENCE/iOS

[Xcode/iOS] 간단한 예제로 Protocol 구현해보기 (with. SwiftUI)

728x90
728x90

 

 

 

728x90

 

 

 

 

 

 

프로토콜(Protocol)이란?
특정 작업 혹은 기능에 적합한 메소드, 프로퍼티, 기타 요구사항들의 청사진

 

 

 

특징

 

  • 클래스, 구조체, 열거형에서 채택될 수 있음
  • 여러개의 프로토콜을 동시에 채택할 수 있음
  • 프로토콜은 이름과 타입만이 지정될 뿐 상세한 내용은 구현하지 않는다

 

 

 

예제
protocol FullyNamed {
    static var firstName : String { get set }
    var mddleName : String { get set }
    var fullName: String { get }
    
    func getName() -> String
    mutating func toggleName()
    
    init(middleName: String)
}

 

 

 

 

 

예제 결과화면

 

 

 

구현

 

  • Money.swift
import Foundation

protocol MoneyProtocol {
    var totalMoney:Int { get }
    var count:Int { get }
    // 데이터 입력
    func enterData(moeny:Int, count:Int)
    // 계산 로직
    func calculate() -> Int
    // 남은 금액
    func remain() -> Int
    // 결과 출력
    func printResult() -> String
}

class DivideMoney : MoneyProtocol {
    var totalMoney: Int = 0
    var count: Int = 0
    
    func enterData(moeny: Int, count: Int) {
        totalMoney = moeny
        self.count = count
    }
    
    func calculate() -> Int {
        return totalMoney / count
    }
    
    func remain() -> Int {
        return totalMoney - calculate() * count
    }
    
    func printResult() -> String {
        let numFormatter = NumberFormatter()
        numFormatter.numberStyle = .decimal
        guard let totalMoney = numFormatter.string(from: NSNumber(value: totalMoney)),
        let result = numFormatter.string(from: NSNumber(value: calculate())) else { return "" }
        var msg = ""
        msg = "총 금액 : \(totalMoney)원\n인원 : \(count)명\n1명당 내야할 금액 : \(result)원"
        if remain() != 0 {
            guard let other = numFormatter.string(from: NSNumber(value: remain())) else { return "" }
            msg += "\n나머지 금액 : \(other)원"
        }
        return msg
    }
}

class GatherMoney : MoneyProtocol {
    var totalMoney: Int = 0
    var count: Int = 0
    
    func enterData(moeny: Int, count: Int) {
        totalMoney = moeny
        self.count = count
    }
    
    func calculate() -> Int {
        return totalMoney / count
    }
    
    func remain() -> Int {
        return totalMoney - calculate() * count
    }
    
    func printResult() -> String {
        let numFormatter = NumberFormatter()
        numFormatter.numberStyle = .decimal
        var msg = ""
        guard let totalMoney = numFormatter.string(from: NSNumber(value: totalMoney)),
        let result = numFormatter.string(from: NSNumber(value: calculate())) else { return "" }
        msg = "총 기간 : \(count)개월\n총 금액 : \(totalMoney)원"
        if remain() == 0 {
            msg += "\n\(count)개월간 내야할 금액 : \(result)원"
        } else {
            guard let other = numFormatter.string(from: NSNumber(value: calculate() + remain())) else { return "" }
            msg += "\n\(count-1)개월간 내야할 금액 : \(result)원\n마지막 달에 내야할 금액 : \(other)원"
        }
        return msg
    }
}
- MoneyProtocol : 전체 금액, 카운트 변수의 정의 / 데이터 입력, 계산, 남은 금액 반환, 결과 출력 함수만 정의 되어 있는 프로토콜
- DivideMoney : MoneyProtocol을 채택하여 입력 받은 전체 금액을 카운트로 나누어 1인당 지불해야할 금액을 계산해주는 클래스
- GatherMoney : MoneyProtocol을 채택하여 입력 받은 금액을 카운트의 기간 동안 모으기 위해서는 기간 별로  얼마씩 저금해야하는지 계산해주는 클래스

 

 

  • ContentView.swift
import SwiftUI

struct ContentView: View {
    @State private var viewIndex = 0
    @State private var people = 0
    @State private var money = ""
    @State private var isShow = false
    @State private var msg = ""
    private var divider:DivideMoney = DivideMoney()
    @FocusState private var isFocused: Bool

    // tapGesture 조건부사용
    private var tapGesture: some Gesture {
        isFocused ?
        (TapGesture().onEnded {
            isFocused = false
        }) : nil
    }
    
    var body: some View {
        TabView(selection: $viewIndex) {
            ZStack {
                VStack {
                    // 나누어야할 금액입력
                    TextField("나눌 금액을 입력하세요", text: $money)
                        .focused($isFocused)
                        .frame(width: 300)
                        .textFieldStyle(.roundedBorder)
                        .keyboardType(.numberPad)
                        .padding(18)
                    // 나눌 인원설정
                    Stepper(value: $people, in: 1...10) {
                        Text(people < 2 ? "나누어야할 인원" : "\(people)명")
                    }
                    .frame(width: 300)
                    // 계산버튼
                    Button {
                        showResult()
                    } label: {
                        Text("계산하기")
                    }
                    .buttonStyle(.bordered)
                    .foregroundColor(.white)
                    .background(.black)
                    .cornerRadius(10)
                    .padding(60)
                    // 결과 메세지 창
                    Text(msg)
                        .foregroundColor(.red)
                }
                .padding(EdgeInsets(top: 30, leading: 18, bottom: 30, trailing: 18))
            }
            .frame(maxWidth: .infinity, maxHeight: .infinity)
            .contentShape(Rectangle())
            .gesture(tapGesture)
            .tabItem {
                Image(systemName: "person.3.sequence.fill")
                Text("돈나누기")
            }
            .tag(0)
            GaterViewView()
                .tabItem {
                    Image(systemName: "arrow.up.bin.fill")
                    Text("돈모으기")
                }.tag(1)
        }
    }
    // 결과보여주기
    func showResult() {
        msg = ""
        // 입력 예외처리
        if money.isEmpty { return }
        guard let inputMoney = Int(money) else { return }
        if people < 2 || inputMoney < 1 { return }
        // 계산 후 메세지 출력
        divider.enterData(moeny: inputMoney, count: people)
        msg = divider.printResult()
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}
money를 n명이 나눌 때 1인 당 지불해야하는 금액을 계산해주는 화면

 

 

  • GatherView.swift
import SwiftUI

struct GaterViewView: View {
    @State private var month = 0
    @State private var money = ""
    @State private var isShow = false
    @State private var msg = ""
    private var gather:GatherMoney = GatherMoney()
    @FocusState private var isFocused: Bool
    
    // tapGesture 조건부사용
    private var tapGesture: some Gesture {
        isFocused ?
        (TapGesture().onEnded {
            isFocused = false
        }) : nil
    }
    
    var body: some View {
        ZStack {
            VStack {
                // 나누어야할 금액입력
                TextField("모을 금액을 입력하세요", text: $money)
                    .focused($isFocused)
                    .frame(width: 300)
                    .textFieldStyle(.roundedBorder)
                    .keyboardType(.numberPad)
                    .padding(18)
                // 기간 설정
                Stepper(value: $month, in: 0...10) {
                    Text(month < 1 ? "기간 설정" : "\(month)개월")
                }
                .frame(width: 300)
                // 계산버튼
                Button {
                    showResult()
                } label: {
                    Text("계산하기")
                }
                .buttonStyle(.bordered)
                .foregroundColor(.white)
                .background(.black)
                .cornerRadius(10)
                .padding(60)
                // 결과 메세지 창
                Text(msg)
                    .foregroundColor(.red)
            }
            .padding(EdgeInsets(top: 30, leading: 18, bottom: 30, trailing: 18))
        }
        .frame(maxWidth: .infinity, maxHeight: .infinity)
        .contentShape(Rectangle())
        .gesture(tapGesture)
    }
    // 결과보여주기
    func showResult() {
        msg = ""
        // 입력 예외처리
        if money.isEmpty { return }
        guard let inputMoney = Int(money) else { return }
        if month < 1 || inputMoney < 1 { return }
        // 계산 후 메세지 출력
        gather.enterData(moeny: inputMoney, count: month)
        msg = gather.printResult()
    }
}

struct GaterViewView_Previews: PreviewProvider {
    static var previews: some View {
        GaterViewView()
    }
}
money를 특정 기간 동안 모을 때 1개월 당 저금해야할 금액을 계산해주는 화면

 

 

 

 

 

 

 

 

 

참고사이트
 

Protocols — The Swift Programming Language (Swift 5.7)

Protocols A protocol defines a blueprint of methods, properties, and other requirements that suit a particular task or piece of functionality. The protocol can then be adopted by a class, structure, or enumeration to provide an actual implementation of tho

docs.swift.org

 

728x90
728x90