스파르타 코딩 클럽 - iOS 스타터 6기/본 캠프

28. 스파르타 코딩 클럽 - 팀 프로젝트 4, 5일차 [마무리]

seongpil Heo 2025. 4. 11. 12:54

 👥 팀 프로젝트 - 키오스크 앱 만들기

오늘은 4월 11일 팀 프로젝트 마지막 날이다.

어제 블로그 작성을 못했는데 그 이유는 각자 역할을 나눠 구현했던 UI를 합치고

데이터를 서로 넘겨주고 받는 로직을 구현하였는데

데이터를 다른 곳으로 넘겨줄 때 Delegate를 사용했다

 

서로 각자의 환경에서 코드를 작성하고 그걸 한 곳에 합치려고 하니까

오류도 많이 발생하고 서로의 로직을 이해하는데 생각보다 시간이 많이 걸렸다.

 

그리고 데이터를 넘겨주는 방법으로 Delegate Pattern을 사용했는데

몇 번 강의도 듣고 튜터님들께서도 설명해 주셨지만 역시나 잘 이해가 된 상태가 아니어서

우리의 팀 코드에 구현하는 것에 어려움이 있었다.

 

다 해결하고 보니 이미 12시가 넘어버려서 블로그를 차마 쓸 시간이 없었다 ㅠㅠ (라는 변명)

쨋든 어제와 오늘 작업한 내용을 몇개 적어보자면...

 

시간이 녹았어요...


1. 장바구니가 비어있을 경우 "장바구니가 비어있습니다."라는 Label 표시

 

[ 구현 방법 ]

1. OrderTable.swift 에서 Label을 하나 추가한다.

2. OrderTable과 같은 크기에 같은 위치에 Label 제약조건을 설정한다.

3. 총 0개   ₩원의 결과 표시를 담당하는 함수 부분에서 isHidden 값을 조절하여

4. 총 개수가 0일 때, Label을 표시하고 0이 아닐 때, Label을 숨기는 처리를 한다.

 

[ 코드 ]

// 장바구니가 비었을 때 표시될 Label을 만드는 함수
private func makeCartLabel() {
        cartLabel.font = .systemFont(ofSize: 15) // 기본 폰트 크기 15 설정
        cartLabel.text = "장바구니가 비어있습니다." // 표시 할 Text 지정
        cartLabel.textAlignment = .center // 글자 정렬 - 가운데
        
        self.addSubview(cartLabel) // Subview에 Label 추가
        
        // Snapkit을 사용한 Label 제약조건
        cartLabel.snp.makeConstraints { make in
            make.leading.equalTo(self.snp.leading) // 상위 뷰에서 정한 leading에 맞춤
            make.top.equalTo(self.snp.top) // 상위 뷰에서 정한 top에 맞춤
            make.width.equalTo(self.snp.width) // OrderTable의 width와 동일하게
            make.height.equalTo(self.snp.height) // OrderTable의 height와 동일하게
        }
        
    }

 

// 장바구니의 Count를 관리하는 함수
func didUpdateCounts() {
        totalCount = 0
        totalPrice = 0
        for item in dataSource {
            let count = item.count
            let price = Int(item.priceLabel.dropLast(1)) ?? 0
            totalCount += count
            totalPrice += count * price
        }
        
        countLabel.text = "총 \(totalCount)개"
        priceLabel.text = "₩ \(totalPrice)원"
        
        
        if totalCount == 0 { // totalCount가 0이면 cartLabel을 화면에 표시
            cartLabel.isHidden = false
        } else { // 아니면 cardLabel을 화면에서 숨김
            cartLabel.isHidden = true
        }
    }
    
    // 새로 알게된 함수 isHidden
    // Swift에서 isHidden은 UIKit의 UIView 클래스(예: UILabel, UIButton, UIImageView 등)에 있는 
    // 속성(property) 중 하나로, 해당 뷰가 화면에 보일지 여부를 제어할 때 사용한다.
    
    label.isHidden = true  // label을 화면에서 숨김
    button.isHidden = false // button을 화면에 보이도록 설정
    
    isHidden은 뷰를 레이아웃에서 제거하진 않는다. 
    → 즉, 숨겨져 있어도 해당 뷰는 메모리에 남아 있고, Auto Layout에도 영향을 미치지 않는다.
	완전히 제거하고 싶다면 removeFromSuperview()를 사용해야 한다.

2. 사용자가 장바구니에 같은 상품을 선택 시 중복으로 담기던 상품을 중복 방지 처리 

장바구니 Label 초기 구현

 

[ 구현 방법 ]

1. orderTable의 dataSource에 새로운 아이템을 추가하는 부분에서 사용자가 같은 상품을 선택했는지 확인

2. 같은 상품을 선택했다면 dataSource배열에 새로 추가하는 것이 아니라 같은 값을 가진 요소에서 count 값을 1증가

3. 다른 상품을 선택했다면 dataSource 배열에 새로 추가

 

[ 코드 ]

// ViewController 안에 있는 sendData함수
// delegate 함수로 컬렉션 뷰와 테이블 뷰를 연결해서 데이터를 넘겨줌

func sendData(name: String, price: String) {
	// 사용자가 클릭한 상품의 정보를 newItem에 받아옴
        let newItem = CustomCellModel(nameLabel: name, priceLabel: price)
		
    // firstIndex함수를 사용하여 dataSource 배열에 이미 있는 상품의 이름과 
    // 새로 사용자가 선택하여 받아온 newItem의 이름이 같은지 확인하고 같으면 해당 인덱스 반환
    if let index = orderTable.dataSource.firstIndex(where: { $0.nameLabel == newItem.nameLabel}) {
        orderTable.dataSource[index].count += 1 // 인덱스로 배열 요소에 접근하여 count 증가
    } else { // 새로운 상품이라면
        orderTable.dataSource.append(newItem) // dataSource 배열에 상품 추가
    }
    orderTable.loadData() // orderTable 데이터 리로드
}

 

[ 🔍 firstIndex 함수란? ]

firstIndex컬렉션(Array, String 등)에서 조건을 만족하는 첫 번째 요소의 인덱스(index)를 찾아주는 함수이다.

기본 문법 - collection.firstIndex(where: 조건식)
• collection: 배열, 문자열 등 반복 가능한 자료형
• where: 뒤에는 조건을 만족하는 클로저(함수)가 들어가요
• 리턴 값은 해당 요소의 인덱스(Int?)이며, 조건을 만족하는 게 없으면 nil을 반환해요

3. 앱 로고 변경과 앱의 이름을 한글로 변경

 

[ 한글 앱 이름 구현 방법 ]

1. String File (Legacy) 파일 생성

String File (Legacy) 파일 생성

 

Navigator 창에서 방금 만든 InfoPlist.strings를 클릭하고, Inspector 창 첫번째 탭의 Localize... 버튼을 눌러준다!

 

2. Localization 추가하기

XCode의 좌측 Navigator에서 프로젝트 폴더를 클릭하고 'PROJECT > Info' 에서 Localizations 부분을 찾는다.

 

+버튼을 눌러 Korean을 추가해준다. 다른 건 해제해주고 InfoPlist.strings만 체크

 

그럼 Navigator와 Inspector를 보면 Korean이 추가된 것을 볼 수 있다.

[ 코드 ]

/* 
  InfoPlist.strings (Korean)
*/
"CFBundleDisplayName" = "오덬";
"CFBundleName" = "오덬";

 

이 코드를 적어주면 사용자의 Language가 Korean일 경우

앱 네임에 오덬 이라고 표시된다.

 

[ 앱 로고 변경 구현 방법 ]

1024 x 1024 크기의 이미지를 준비한 뒤

Assets.xcassets 파일 안에 넣어주면 된다.

Simple!


 🎥 최종 프로젝트 시연 영상


🖼️ 앱 소개 이미지

다성님이 만들어주신 앱 소개 이미지 (무한 감사) 🙇‍♂️
팀 README에 바로 넣었습니다 ㅎㅎ


✓ TIL

5일 동안 팀 프로젝트를 진행하면서 많은 것들을 배울 수 있었다.

협업 시 GitHub 사용 방법, 커밋 컨벤션, 코드리뷰, Git conflict, branch 룰 & 전략, Figma 등등

 

5일동안 밤낮으로 팀원들과 작업하면서 많이 친해지고, 서로에게서 좋은 점들을 배울 수 있었다.

또한 개인적으로도 한 발짝 더 성장하는 계기가 되었다.

 

내가 작성한 코드를 다른 팀원들에게 설명하고, 팀원들이 이해할 수 있도록

코드를 간결하고 명확하게 작성해야 한다는 점도 배웠다.

기능을 구현할 때 이 코드를 왜 작성했는지, 각 기술의 장단점을 알고 사용할 수 있도록 많은 공부가 필요할 것 같다.

 

개인적으로 이번 프로젝트에 만족한다.

필수 기능 구현도 완료하고, 팀원들과 머리를 싸매며 아이디어 회의를 하고,

오류를 찾아서 고치고, 새로운 기능을 추가하고...

묵묵하게 각자의 작업을 완성하고, 서로를 잘 도와주신 팀원들에게 감사한 마음이다.

 

우리 오합지존 다들 고생하셨습니다! 다음에 또 만나요! 😄