꾸준히 안타치기
② Picker View - customPlist / 커스텀 본문
반응형
피커뷰 구현하기 ( 계정 텍스트뷰를 누르면 화면하단에 피커뷰 등장 )
- 피커뷰는 셀렉트나 콤보박스 등의 기능을 하는 입력용뷰이다. 이미지피커뷰와는 전혀연관이 없다.
- 피켜뷰와 테이블뷰는 유사하다. 차이점은 테이블뷰는 UITableViewCell객체를 생성해야하는것 외에 유사함.
- 피커뷰는 문자열을 아이템으로 갖는 배열 타입의 데이터 소스를 사용한다.
메인스토리보드를 열고 테이블뷰추가 +네비게이션 컨트롤러 임베디드한다.
테이블뷰 셀을 정적으로 변경
테이블뷰 셀 추가
아래와 같이 화면구성하기
UserDefaluts | 계정목록은 공통정보 이므로, 기본저장소에서 관리 | 계정목록 저장 |
Plist | 데이터를 분리하여 저장할때 편리 / 계정별로 반복되는 정보를 따로 저장해야할때 사용한다. UserDefaluts는 키가 같으면 덮어쓰기기 됨 |
앱에서 마지막으로 선택된 계정정보 |
UserDefalut (accountList에 저장) |
A@email.com B@email.com C@email.com |
Plist (selectedAccount에 저장) | |||||
A.plist | B.plist | C.plist | |||
key | value | key | value | key | value |
account | A | account | B | account | C |
A@email.com | B@email.com | C@email.com | |||
updateFlag | false | updateFlag | true | updateFlag | false |
현재선택되어 있는 계정에 맞는 커스텀 Plist 파일을 읽어와야한다. / 데이터 저장하기
선택된 사용자정보 가져오기
1. UserDefaults 코드를 삭제하고, 이름을 커스텀프로퍼티 리스트에 저장한다.
//테이블뷰에 대한 델리게이트 메소드를 추가.
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if indexPath.row == 1 && !(self.account.text?.isEmpty)!{ //두번째 셀이 클릭되었을때
//입력이 가능한 알림창을 띄워 이름을 수정할수 있게한다.
let alert = UIAlertController(title: nil, message: "이름을 입력하세요", preferredStyle: .alert)
//입력필드 추가
alert.addTextField(){
$0.text = self.name.text // 이름레이블의 텍스트 넣어주기
}
// 버튼 및 액션 추가
alert.addAction(UIAlertAction(title: "OK", style: .default){(_) in
//사용자가 OK버튼을 누르면 입력 필드에 입력된 값을 저장한다.
let value = alert.textFields?[0].text
// 커스텀프로퍼티에 저장$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
// 현재입력된 계정을 바탕으로 읽어올 커스텀 프로퍼티 파일명을 정의한다.
let customPlist = "\(self.account.text!).plist" // 읽어올 파일명
// 앱 내에 생성된 문서 디렉터리 경로를 구한다.
let paths = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)
let path = paths[0] as NSString
let plist = path.strings(byAppendingPaths: [customPlist]).first!
//읽어온 파일을 딕셔너리 객체로 변환한다. 만약 해당위치에 파일이 없다면 새로운 딕셔너리 객체를 생성한다.
let data = NSMutableDictionary(contentsOfFile: plist) ?? NSMutableDictionary()
// 입력된 이름값을 딕셔너리 객체에 "name"키로 저장한다.
data.setValue(value, forKey: "name")
// 딕셔너리객체를 커스텀 프로퍼티 파일로 저장한다.
data.write(toFile: plist, atomically: true)
self.name.text = value
})
//알림창띄움
self.present(alert, animated: false, completion: nil)
}
}
2. 성별과, 결혼여부도 커스텀프로퍼티리스트에 gender,married키로 저장
// 성별액션메소드
@IBAction func changeGender(_ sender: UISegmentedControl) {
let value = sender.selectedSegmentIndex //0이면 남자, 1이면 여자
// let plist = UserDefaults.standard // 기본객체저장소를 가져옴
// plist.set(value, forKey: "gender")//젠더라는키로 가져옴
// plist.synchronize()// 동기화
// 커스텀프로퍼티에 저장$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
let customPlist = "\(self.account.text!).plist" // 읽어올파일명
let paths = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)
let path = paths[0] as NSString
let plist = path.strings(byAppendingPaths: [customPlist]).first!
//읽어온 파일을 딕셔너리 객체로 변환한다. 만약 해당위치에 파일이 없다면 새로운 딕셔너리 객체를 생성한다.
let data = NSMutableDictionary(contentsOfFile: plist) ?? NSMutableDictionary()
// 입력된 이름값을 딕셔너리 객체에 "name"키로 저장한다.
data.setValue(value, forKey: "gender")
// 딕셔너리객체를 커스텀 프로퍼티 파일로 저장한다.
data.write(toFile: plist, atomically: true)
}
// 결혼여부액션메소드
@IBAction func changeMarried(_ sender: UISwitch) {
let value = sender.isOn //트루면 기혼
// let plist = UserDefaults.standard
// plist.set(value, forKey: "married")
// plist.synchronize()
// 커스텀프로퍼티에 저장$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
let customPlist = "\(self.account.text!).plist" // 읽어올파일명
let paths = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)
let path = paths[0] as NSString
let plist = path.strings(byAppendingPaths: [customPlist]).first!
//읽어온 파일을 딕셔너리 객체로 변환한다. 만약 해당위치에 파일이 없다면 새로운 딕셔너리 객체를 생성한다.
let data = NSMutableDictionary(contentsOfFile: plist) ?? NSMutableDictionary()
// 입력된 이름값을 딕셔너리 객체에 "name"키로 저장한다.
data.setValue(value, forKey: "married")
// 딕셔너리객체를 커스텀 프로퍼티 파일로 저장한다.
data.write(toFile: plist, atomically: true)
print("custom plist = \(plist)")
}
3. 저장된 커스텀프로퍼티파일 꺼내 화면에 표시하기
신규계정등록과 동시에 계정을 선택한 것으로 간주하고, selectedAccount키로 저장됨 / 그것을 꺼냄
피커뷰의 Done버튼을 눌렀을때 불러옴
// 피커뷰 닫기버튼
@objc func pickerDone(_ sender: Any){
self.view.endEditing(true)
// 사용자가 계정을 변경했을때 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//선택된 계정에 대한 커스텀 프로퍼티 파일을 읽어와 세팅한다.
if let _account = self.account.text {
let customPlist = "\(_account).plist" //읽어올 파일명
let paths = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)
let path = paths[0] as NSString
let clist = path.strings(byAppendingPaths: [customPlist]).first!
let data = NSDictionary(contentsOfFile: clist)
self.name.text = data?["name"] as? String
self.gender.selectedSegmentIndex = data?["gender"] as? Int ?? 0
self.married.isOn = data?["married"] as? Bool ?? false
}
}
계정정보 미등록시 사용자 정보 입력막기
// 사용자의 계정의 값이 비어 있다면 값을 설정하는 것을 막는다.************************************************
if(self.account.text?.isEmpty)!{
self.account.placeholder = "등록된 계정이 없습니다."
self.gender.isEnabled = false
self.married.isEnabled = false
}
이름 비어있을때는 실행되지 않게
//테이블뷰에 대한 델리게이트 메소드를 추가.
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if indexPath.row == 1 && !(self.account.text?.isEmpty)!{ //두번째 셀이 클릭되었을때
사용자가 계정을 새로등록하면 비활성화되어 있던 컨트롤을 활성화 시켜 주어야한다.
그래야 성별과 결혼여부 변경할수 있다.
// 계정추가버튼
@objc func newAccount(_ sender: Any){
// 일단 열려있는 입력용 뷰부터 닫아준다.
self.view.endEditing(true)
//알림창 객체 생성
let alert = UIAlertController(title: "새 계정을 입력하세요", message: nil, preferredStyle: .alert)
//입력폼 추가
alert.addTextField(){
$0.placeholder = "ex) abc@gmail.com"
}
//버튼 및 액션 정의
alert.addAction(UIAlertAction(title: "OK", style: .default){ (_) in
if let account = alert.textFields?[0].text {
self.gender.isEnabled = true
self.married.isEnabled = true
//네비게이션 바의 오른쪽에 바버튼을 추가하고 클릭시 new Account메소드 실행
let addBtn = UIBarButtonItem(barButtonSystemItem: .add, target: self, action: #selector(newAccount(_:)))
self.navigationItem.rightBarButtonItems = [addBtn]
전체코드
import UIKit
class ListViewController :UITableViewController ,UIPickerViewDelegate,UIPickerViewDataSource{
@IBOutlet weak var account: UITextField!
// 계정목록을 담을 배열정의
var accountlist = [String]()
@IBOutlet weak var name: UILabel! // 이름
@IBOutlet weak var gender: UISegmentedControl!//성별
@IBOutlet weak var married: UISwitch!//결혼여부
//피커뷰ㅍ
override func viewDidLoad() {
//기본 저장소 객체 불러오기
let plist = UserDefaults.standard
//불러온 값을 설정
self.name.text = plist.string(forKey: "name")//이름
self.married.isOn = plist.bool(forKey: "married")//성별
self.gender.selectedSegmentIndex = plist.integer(forKey: "gender")//결혼여부
let picker = UIPickerView()
//피커뷰의 델리게이트 객체 지정
picker.delegate = self
//account 텍스트필드 입력 방식을 가상 키보드 대신 피커뷰로 설정
self.account.inputView = picker
//툴바 객체 정의
let toolbar = UIToolbar()
toolbar.frame = CGRect(x: 0, y: 0, width: 0, height: 35)
toolbar.barTintColor = .lightGray
//액세서리 뷰 영역에 툴바를 표시
self.account.inputAccessoryView = toolbar
//툴바에 들어갈 닫기 버튼
let done = UIBarButtonItem()
done.title = "Done"
done.target = self
done.action = #selector(pickerDone)// 닫기메소드
//신규계정등록버튼
let new = UIBarButtonItem()
new.title = "New"
new.target = self
new.action = #selector(newAccount(_:))// 계정추가메소드
// 가변 폭 버튼 정의
let flexSpace = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil)
//버튼을 모두 툴바에 추가 뉴버튼 / 사이공간 / 닫기버튼
toolbar.setItems([new,flexSpace,done], animated: true)
// 사용자의 계정의 값이 비어 있다면 값을 설정하는 것을 막는다.************************************************
if(self.account.text?.isEmpty)!{
self.account.placeholder = "등록된 계정이 없습니다."
self.gender.isEnabled = false
self.married.isEnabled = false
}
// 계정정보 읽어오기 /////////////////////////////////////////////////////////////////////////////
// accountlist키 로 저장된 값을 읽어온다. 저장된 값이 없을 경우 새로운 배열객체를 생성한다.
let accountlist = plist.array(forKey: "accountlist") as? [String] ?? [String]()
// 읽어온값을 멤버변수에 대입한다.
self.accountlist = accountlist
//1. selectedAccount키에 저장된 값이 있으면, 이를 사용하여 읽어와야할 파일의 이름을 구성한다.
if let account = plist.string(forKey: "selectedAccount"){
// 값이 있을경우에 account의 텍스트 필드 값으로 대입한다.
self.account.text = account
// 저장된 프로퍼티파일 가져오기 $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
let customPlist = "\(account).plist" //읽어올 파일명
//2. 앱내에 정의된 문서 디렉토리 경로를 가져온 다음 파일명을 조합하여 전체 경로를 구성한다.
let paths = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)
let path = paths[0] as NSString
let clist = path.strings(byAppendingPaths: [customPlist]).first!
// 3.저장된파일을 읽어와서 딕셔너리 객체로 전환한다.
let data = NSDictionary(contentsOfFile: clist)
// name키에 저장된 값을 꺼내어 이름 레이블에 세팅한다.
self.name.text = data?["name"] as? String
// 젠더 키에 저장된 값을 꺼내여 세그먼트 컨트롤에 세팅한다. 만약 값이 없다면 0으로 설정한다.
self.gender.selectedSegmentIndex = data?["gender"] as? Int ?? 0
//married키에 저장된 값을 꺼내어 스위치 컨트롤에 세팅한다. 만약 값이 없다면 false로 설정
self.married.isOn = data?["married"] as? Bool ?? false
}
//네비게이션 바의 오른쪽에 바버튼을 추가하고 클릭시 new Account메소드 실행
let addBtn = UIBarButtonItem(barButtonSystemItem: .add, target: self, action: #selector(newAccount(_:)))
self.navigationItem.rightBarButtonItems = [addBtn]
}
//생성할 컴포턴트의 갯수를 정의합니다.
func numberOfComponents(in pickerView: UIPickerView) -> Int {
return 1
}
//지정된 컴포턴트가 가질 목록의 길이를 정의합니다.
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
return self.accountlist.count
}
// 지정된 컴포넌트의 목록 각 행에 출력될 내용을 정의합니다.행번호에 맞게출력된다.
func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
return self.accountlist[row]
}
// 지정된 컴포넌트의 목록 각 행을 사용자가 선택했을 때 실행할 액션을 정의합니다.
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
// 선택된 계정값을 텍스트 필드에 입력
let account = self.accountlist[row]
self.account.text = account
//사용자가 계정을 생성하면 이 계정을 선택한 것을 간주하고 저장한다.@@@@@@@@@@@@@@@@@@@@@@@@@
let plist = UserDefaults.standard
plist.set(account, forKey: "selectedAccount")
plist.synchronize()
// 입력 뷰를 닫음
// self.view.endEditing(true)
}
// 피커뷰 닫기버튼
@objc func pickerDone(_ sender: Any){
self.view.endEditing(true)
// 사용자가 계정을 변경했을때 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//선택된 계정에 대한 커스텀 프로퍼티 파일을 읽어와 세팅한다.
if let _account = self.account.text {
let customPlist = "\(_account).plist" //읽어올 파일명
let paths = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)
let path = paths[0] as NSString
let clist = path.strings(byAppendingPaths: [customPlist]).first!
let data = NSDictionary(contentsOfFile: clist)
self.name.text = data?["name"] as? String
self.gender.selectedSegmentIndex = data?["gender"] as? Int ?? 0
self.married.isOn = data?["married"] as? Bool ?? false
}
}
// 게정추가버튼
@objc func newAccount(_ sender: Any){
// 일단 열려있는 입력용 뷰부터 닫아준다.
self.view.endEditing(true)
//알림창 객체 생성
let alert = UIAlertController(title: "새 계정을 입력하세요", message: nil, preferredStyle: .alert)
//입력폼 추가
alert.addTextField(){
$0.placeholder = "ex) abc@gmail.com"
}
//버튼 및 액션 정의
alert.addAction(UIAlertAction(title: "OK", style: .default){ (_) in
if let account = alert.textFields?[0].text {
self.gender.isEnabled = true
self.married.isEnabled = true
//계정 목록 배열에 추가한다.
self.accountlist.append(account)
//계정 텍스트 필드에 표시한다.
self.account.text = account
//컨트롤 값을 모두 초기화한다.
self.name.text = ""
self.gender.selectedSegmentIndex = 0
self.married.isOn = false
// 계정 목록을 통째로 저장한다.@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
let plist = UserDefaults.standard
plist.set(self.accountlist, forKey: "accountlist")
// 신규로 등록시 계정값을 받아서 selectedAccount키로 저장한다.
plist.set(account, forKey: "selectedAccount")
plist.synchronize()
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
}
})
//알림창 오픈
self.present(alert, animated: false, completion: nil)
}
// 성별액션메소드
@IBAction func changeGender(_ sender: UISegmentedControl) {
let value = sender.selectedSegmentIndex //0이면 남자, 1이면 여자
// let plist = UserDefaults.standard // 기본객체저장소를 가져옴
// plist.set(value, forKey: "gender")//젠더라는키로 가져옴
// plist.synchronize()// 동기화
// 커스텀프로퍼티에 저장$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
let customPlist = "\(self.account.text!).plist" // 읽어올파일명
let paths = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)
let path = paths[0] as NSString
let plist = path.strings(byAppendingPaths: [customPlist]).first!
//읽어온 파일을 딕셔너리 객체로 변환한다. 만약 해당위치에 파일이 없다면 새로운 딕셔너리 객체를 생성한다.
let data = NSMutableDictionary(contentsOfFile: plist) ?? NSMutableDictionary()
// 입력된 이름값을 딕셔너리 객체에 "name"키로 저장한다.
data.setValue(value, forKey: "gender")
// 딕셔너리객체를 커스텀 프로퍼티 파일로 저장한다.
data.write(toFile: plist, atomically: true)
}
// 결혼여부액션메소드
@IBAction func changeMarried(_ sender: UISwitch) {
let value = sender.isOn //트루면 기혼
// let plist = UserDefaults.standard
// plist.set(value, forKey: "married")
// plist.synchronize()
// 커스텀프로퍼티에 저장$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
let customPlist = "\(self.account.text!).plist" // 읽어올파일명
let paths = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)
let path = paths[0] as NSString
let plist = path.strings(byAppendingPaths: [customPlist]).first!
//읽어온 파일을 딕셔너리 객체로 변환한다. 만약 해당위치에 파일이 없다면 새로운 딕셔너리 객체를 생성한다.
let data = NSMutableDictionary(contentsOfFile: plist) ?? NSMutableDictionary()
// 입력된 이름값을 딕셔너리 객체에 "name"키로 저장한다.
data.setValue(value, forKey: "married")
// 딕셔너리객체를 커스텀 프로퍼티 파일로 저장한다.
data.write(toFile: plist, atomically: true)
print("custom plist = \(plist)")
}
//테이블뷰에 대한 델리게이트 메소드를 추가.
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if indexPath.row == 1 && !(self.account.text?.isEmpty)!{ //두번째 셀이 클릭되었을때
//입력이 가능한 알림창을 띄워 이름을 수정할수 있게한다.
let alert = UIAlertController(title: nil, message: "이름을 입력하세요", preferredStyle: .alert)
//입력필드 추가
alert.addTextField(){
$0.text = self.name.text // 이름레이블의 텍스트 넣어주기
}
// 버튼 및 액션 추가
alert.addAction(UIAlertAction(title: "OK", style: .default){(_) in
//사용자가 OK버튼을 누르면 입력 필드에 입력된 값을 저장한다.
let value = alert.textFields?[0].text
// let plist = UserDefaults.standard
// plist.setValue(value,forKey: "name")
// plist.synchronize()
// 커스텀프로퍼티에 저장$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
// 현재입력된 계정을 바탕으로 읽어올 커스텀 프로퍼티 파일명을 정의한다.
let customPlist = "\(self.account.text!).plist" // 읽어올 파일명
// 앱 내에 생성된 문서 디렉터리 경로를 구한다.
let paths = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)
let path = paths[0] as NSString
let plist = path.strings(byAppendingPaths: [customPlist]).first!
//읽어온 파일을 딕셔너리 객체로 변환한다. 만약 해당위치에 파일이 없다면 새로운 딕셔너리 객체를 생성한다.
let data = NSMutableDictionary(contentsOfFile: plist) ?? NSMutableDictionary()
// 입력된 이름값을 딕셔너리 객체에 "name"키로 저장한다.
data.setValue(value, forKey: "name")
// 딕셔너리객체를 커스텀 프로퍼티 파일로 저장한다.
data.write(toFile: plist, atomically: true)
self.name.text = value
})
//알림창띄움
self.present(alert, animated: false, completion: nil)
}
}
}
반응형
'iOS > 기본편 | 실전편 -꼼꼼한재은씨' 카테고리의 다른 글
SideBar / 새글작성 눌러 -> 프론트뷰로 화면전환 (0) | 2022.02.16 |
---|---|
SideBar / 라이브러리 사용X (0) | 2022.02.15 |
① Picker View - userDefault (0) | 2022.02.11 |
UserDefaults (0) | 2022.02.10 |
SideBar / SWRevealViewController 라이브러리 사용 (0) | 2022.02.09 |
Comments