이 'soko' 앱의 핵심 기능은 "유통기한이 있는 음식물을 리스트로 만들어 관리하고, 필요시 알림을 해주는 것"이다. 그외의 기능은 결국 부가적인 기능이다. 따라서 핵심기능부터 완성해볼 것이다. 지난 탭 바로 나눠진 여러개의 View Controller 중에서 '내 냉장고'에 해당하는 탭의 기능을 구현해 본다.


 먼저 '내 냉장고'에 해당하는 View Controller를 클릭하고, 상단 메뉴의 [Editor] - [Embeded In] - [Navigation Controller]를 선택한다. 그럼 기존의 View Controller가 Navigation 형식으로 바뀌는 것을 볼 수 있다. 다른 View Controller에서도 Navigation Controller 형태로 만들 것이므로 모두 적용해 준다.




 Navigation Bar의 오른쪽에 생성된 ViewController를 선택하여 Delete키를 눌러 삭제하고, 오른쪽 하단의 Object library에서 Table View Controller를 끌어 화면에 놓고 Navigation Controller와 연결해주자.

 



 이제 Navigation Bar의 가운데 부분을 더블클릭 하면 제목을 입력할 수 있는 공간이 나타난다. 제목을 입력해 주자. 그리고 Xcode의 우측 하단의 [Show the Object library]에서 [Bar Button Item]을 찾아 Navigation Bar의 우측 상단에 놓아준다. 그리고 추가한 버튼을 클릭하여 Xcode 우측 상단의 [Show the Attribute Inspector]에서 System Item을 [Add]로 바꿔준다.

 






 

 이 상태에서 실행을 해 보면 다음과 같이 표시된다.


 목록이 존재하지 않는데도 여러개의 줄로 구분 되어있음을 알 수 있다. 목록이 없을 때에는 이러한 줄 구분이 안보이게 하기 위해 아무것도 존재하지 않는 View를 View Controller 안에 추가해 준다.


그럼 아래와 같이 내용이 없는 경우 줄이 표시되지 않는다.


 이제 테이블 뷰에 임의로 목록을 추가해 보자. 먼저 테이블 뷰의 Cell을 클릭한다. 화면 왼쪽의 Document Outline에서 직접 선택해 주어도 좋다. 그리고 우측의 [Attribute Inspector]에서 Identifier를 'SokoCell'로 바꾸고, Style을 'Subtitle'로 바꿔주었다.






 이렇게 설정한 셀은 실제로 화면에 표시되는게 아니라 서식을 만든 것 뿐이다. Custom형태로 서식을 만들 수 있으며 이는 기능이 완성된 후에 나중에 바꿀 것이다. 여러개의 셀을 Main.Storyboard에서 만드는게 아니라, 여기서 만든 서식을 코딩을 통해 여러개를 표시할 수 있도록 할 것이다. 왼쪽에서 'soko' 그룹에서 오른쪽 클릭하고 [New Group]을 누른 후, 생성된 그룹의 이름을 'refrigerator'로 만든다. 이 그룹에서는 '내 냉장고'에 해당하는 코드를 입력한 swift파일을 관리할 것이다.


 다시 refrigerator 그룹을 우클릭하고 [New File...]을 선택하고 Swift File을 선택한 후, 이름을 RefrigeratorTableViewController.swift로 만든다. 그리고 아래의 코드를 작성한다.


RefrigeratorTableViewController.swift

import UIKit

class RefrigeratorTableViewController : UITableViewController {

}

 위의 코드 안에서 이제 이 TableViewController를 조작하는 코드를 작성할 것이다.

 다시 Main.storyboard를 클릭하고, 우리가 생성한 TableViewController를 선택하고 우측 상단의 [Identity Inspector]에서 Class를 우리가 방금 만든 RefrigeratorTableViewController를 선택한다. 이렇게 Class를 선택하면 위에서 생성한 Swift파일과 Storyboard의 TableViewController가 연결 된 것이다.


 


 이제 직접 임의의 데이터를 넣어 화면에 출력시켜보자. 먼저 음식에 관한 데이터를 가지고 있는 ValueObject 클래스를 만든다.


FoodVO.swift

import Foundation

class FoodVO {
    init () {
    }

    var name : String?
    var sellByDate : Date?
    var category : FoodCategory?
}


FoodCategory라는 타입은 열거형 객체이다. 아래와 같이 선언하였다.


FoodCategory.swift

import Foundation

enum FoodCategory : Int {
    case Grain, Potato, Sugars, Pulses, SeedsAndNuts, Vegetables, Mushrooms, Fruits, Meat, Eggs, Seafoods, Seaweed, MilkProducts, FatAndOils, Drinks, Seasoning, Etc
}


 이제 TableViewController에 데이터를 추가해 보자. 먼저 구현한 코드를 보자.


RefrigeratorTableViewController.swift

import UIKit

class RefrigeratorTableViewController : UITableViewController {
    var list = Array<FoodVO>()
    var dateFormat = DateFormatter()
    
    override func viewDidLoad() {
        dateFormat.dateFormat = "yyyy-MM-dd"
        dateFormat.locale = Locale.init(identifier: "ko_KR")
        
        var fvo = FoodVO()
        fvo.name = "서울우유"
        fvo.category = FoodCategory.MilkProducts
        fvo.sellByDate = dateFormat.date(from: "2017-04-20")
        list.append(fvo)
        
        fvo = FoodVO()
        fvo.name = "3분짜장"
        fvo.category = FoodCategory.Etc
        fvo.sellByDate = dateFormat.date(from: "2017-07-31")
        list.append(fvo)
    }
    
    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return list.count
    }
    
    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let row = list[indexPath.row]
        let cell = tableView.dequeueReusableCell(withIdentifier: "SokoCell")!
        cell.textLabel?.text = row.name
        cell.detailTextLabel?.text = "유통기한: \(dateFormat.string(from: row.sellByDate!))"
        
        return cell
    }
    
    override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        NSLog("Touch Table Row at %d", indexPath.row)
    }
}


 viewDidLoad() 메서드는 해당 ViewController가 화면에 표시될 때 가장 먼저 실행되는 메서드다. 따라서 override하여 정의해야 내가 원하는 기능을 추가 할 수 있다. 위의 코드에서는 dateFormat을 초기화 하고, 임의의 데이터를 직접 list에 추가하는 코드를 작성하였다. 실제 앱을 작성할 때에는 여기에 직접 데이터를 입력하지 않고 iOS 내부의 데이터베이스에서 데이터를 가져오거나, 웹을 통해 호출해 저장해야 할 것이다.

 tableView(_ tableView:, numberOfRowsInSection section: Int) -> Int 메서드는 몇 개의 줄이 표시되어야 하는지 반환하는 함수이다. 앱이 이 메서드를 호출하여 몇 개의 줄이 필요한지 확인할 것이다. 현재 코드에서는 list라는 배열의 크기만큼 리스트를 표시할 것이다.

 tableView(_ tableView:, cellForRowAt indexPath:) -> UITableViewCell 메서드는 Cell을 반환한다. 즉 여기서 Cell을 생성하고, Cell안에 표시할 내용을 추가하고 앱에 반환하는 것이다. 여기서는 list에서 VO를 불러와 각 내용을 textLabel과 detailTextLabel에 추가하였다.

 tableView(_ tableView:, didSelecRowAt indexPath:) 메서드는 Cell을 클릭했을 때 어떠한 행동을 할 것인지 정의하는 메서드이다.


 이제 다시 실행 해보자.


 이제 '+'버튼을 누르면 '재료 추가' 뷰로 이동하도록 바꿔보자. 먼저 새로운 ViewController를 만들고 아래와 같이 구성한다.


 그리고 기존 테이블 뷰 컨트롤러의 +버튼을 ctrl 버튼을 누른채로 드래그한 후 새로 만든 ViewController에 드롭하면 아래와 같은 창이 뜬다. [Present Modally]를 선택한다. 그럼 두 ViewController가 연결되는 것을 볼 수 있다. 앱을 실행하면 +버튼을 누르면 새로 생성한 ViewController로 넘어가게 된다.




 앱을 실행하면 '+' 버튼을 눌렀을때 오른쪽 View Controller는 표시 되지만, 다시 돌아오는건 작동하지 않는다. unwind 기능을 추가하여야 한다. unwind 메서드는 돌아가고자 하는 컨트롤러에서 작성해야 한다.


RefrigeratorTableViewController.swift

import UIKit

class RefrigeratorTableViewController : UITableViewController {
    
    (... 생략 ...)
    
    @IBAction func unwindToMainViewController(segue : UIStoryboardSegue) {
        
    }
    
    @IBAction func unwindToMainViewControllerAndRefreshList(seque : UIStoryboardSegue) {
        
    }

}


 unwindToMainViewController는 '닫기' 버튼을 눌렀을때 실행될 메서드이고 unwindToMainViewControllerAndRefreshList는 '추가' 버튼을 눌렀을 때 리스트를 새로고침 하기 위한 메서드이다.

 이제 스토리보드에서 '닫기' 버튼을 ctrl을 누른채 드래그하여 ViewController 상단의 세번재 아이콘인 [Exit]에 드롭한다. 그리고 unwindToMainViewController에 연결한다. 마찬가지로 '추가' 버튼도 연결한다.

 


이제 앱을 실행하면 추가 페이지가 열리고 닫히는 모습을 볼 수 있다.



 다음에는 데이터베이스에 이 재료 object들을 저장할 것이다. SQLite를 사용하려 계획하였으나 최근 Realm이라는 데이터베이스가 각광받는다기에 학습하며 적용해 보려 한다. 현재 위의 코드에서 재료 추가 뷰에서 값을 입력받아 데이터베이스에 저장하고, 데이터베이스에서 다시 값을 읽어와 리스트에 출력할 것이다.

+ Recent posts