일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
- 스위프트 테이블 뷰 셀
- 스위프트 카메라
- 안드로이드 앨범
- 노티피케이션 익스텐션
- FlutterView MethodChannel
- Flutter UIKitView MethodChannel
- native flutter view
- 앱 백그라운드 푸시 데이터 저장
- 앱 꺼졌을 때 푸시 데이터 저장
- 푸시 데이터 저장
- Swift flutterview
- flutter 회전
- 안드로이드 에러
- swift sms
- swift autolayout
- 스위프트 앨범
- 스위프트 웹뷰
- swift 문자
- 안드로이드 숏컷
- 안드로이드 바로가기
- flutter rotate
- 스위프트 UserDefaults
- 스위프트
- silent push
- NotificationService Extension
- Swift flutterviewcontroller
- 안드로이드 FCM
- Flutter NativeView
- 스위프트 푸시
- 플러터 뷰 컨트롤러
- Today
- Total
Things take time
[SWIFT] 5일차 : 스위프트 기본 앱 본문
1. Alert에서 문자열 가져오기 및 텍스트 필드 추가, 그리고 ActionSheet(안드로이드의 multiitem alert)
import UIKit class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view, typically from a nib. } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } @IBAction func alertClicked(_ sender: UIButton) { let alert = UIAlertController(title: "알림", message: "메시지", preferredStyle: .alert) alert.addAction(UIAlertAction(title: "OK", style: .default, handler: { (action) in if let text = alert.textFields?[0].text{ print(text) } })) //텍스트 필드 추가 alert.addTextField(configurationHandler: { (textField) in textField.textAlignment = NSTextAlignment.center }) self.present(alert, animated: true, completion: nil) } @IBAction func actionSheetClicked(_ sender: UIButton) { // 이 후 활용 시, handler부분에서 매개변수를 받는 공통 함수를 만들 것 let actionSheet = UIAlertController(title: "선택", message: "선택해주세요", preferredStyle: .actionSheet) actionSheet.addAction(UIAlertAction(title: "냉장고", style: .default, handler: {(Action) -> Void in print("냉장고 선택") })) /* 클로저 사용시 핸들러 분리 가능 actionSheet.addAction(UIAlertAction(title: "냉장고", style: .default) {(Action) -> Void in print("냉장고 선택") }) */ actionSheet.addAction(UIAlertAction(title: "세탁기", style: .default, handler: nil)) actionSheet.addAction(UIAlertAction(title: "텔레비전", style: .default, handler: nil)) actionSheet.addAction(UIAlertAction(title: "삭제", style: .destructive, handler: nil)) actionSheet.addAction(UIAlertAction(title: "취소", style: .cancel, handler: nil)) self.present(actionSheet, animated: true, completion: nil) } }
- 텍스트 필드 추가는 alert의 default만 가능하며 actionsheet에는 텍스트 필드 추가가 불가능함
* 디버깅
- 4번째 : 브레이크 포인트 다음 줄 실행
- 5번째 : 함수 안으로
- 6번째 : 함수 밖으로
2. try catch, throw
import UIKit class ViewController: UIViewController { // 데이터 파싱 시 에러를 체크할 열거형, 에러 프로토콜을 상속받아야 함 enum ParseError: Error { case OverSize case UnderSize case InvalidFormat(value: String) case InvalidData(value: String) } struct Time { var hour: Int = 0 var min: Int = 0 var sec: Int = 0 } override func viewDidLoad() { super.viewDidLoad() // throw를 사용하는 함수 호출 시 : do try catch do { let time = try parseTime(param: "10:28:ㅁㄹ") print(time) } catch ParseError.OverSize { print("문자열 길이 초과") } catch ParseError.UnderSize { print("문자열 길이 미만") } catch ParseError.InvalidFormat(let message) { print("형식 오류 : \(message)") } catch ParseError.InvalidData(let message) { print("값 오류 : \(message)") } catch { print("알 수 없는 오류") } } // try catch를 사용하려면 throws 키워드를 사용해야 함 // param format은 HH:MM:SS로 받을 것으로 결정 func parseTime(param: NSString) throws -> Time{ // return value var returnTime = Time() guard param.length == 8 else { // 길이가 8이 아니면 거짓으로 판명 if param.length > 8 { throw ParseError.OverSize } else { throw ParseError.UnderSize } } // if let으로 unwrapping, 처음부터 2까지 // else는 Int 형 변환이 안됐을 경우, 문자열이 들어온 경우 if let hour = Int(param.substring(to: 2)) { guard hour >= 0 && hour < 24 else { throw ParseError.InvalidData(value: "Hour Invalid Data") } returnTime.hour = hour } else { throw ParseError.InvalidFormat(value: "Not Number") } // substring(with: NSRange(시작, 시작부터 몇 개)) if let min = Int(param.substring(with: NSRange(location: 3, length: 2))) { guard min >= 0 && min < 60 else { throw ParseError.InvalidData(value: "Minutes Invalid Data") } returnTime.min = min } else { throw ParseError.InvalidFormat(value: "Not Number") } // 6번째 부터 끝까지 if let sec = Int(param.substring(from: 6)){ guard sec >= 0 && sec < 60 else { throw ParseError.InvalidData(value: "Second Invalid Data") } returnTime.sec = sec } else { throw ParseError.InvalidFormat(value: "Not Number") } return returnTime } }
실행 결과
- throw사용 시, 열거형 사용할 경우 Error 프로토콜 상속받을 것, throw 데이터 타입이 Error타입
- throw함수 작성 시 return 타입이 throw이며, throw 구문 사용시 그 안에 return이 들어가 있어 따로 작성하지 않아도 됨
- thorw함수 호출 시 do try catch 문법을 사용할 것
- do try catch 문법 확인 (try부분에는 throw함수만 들어감)
3. 테이블 뷰 : 기본, 커스터마이징 없이 기본 내장된 테이블 뷰 컨트롤러 이용시
import UIKit // TableViewController는 딜리게이트, 데이터 소스 변수가 이미 선언되어있어 따로 쓸 필요 없음(기본 테이블 뷰를 사용할 경우만) class TableViewController: UITableViewController { var todoArray = ["영화보기", "여행가기", "게임하기"] var iconArray = ["cart.png", "clock.png", "pencil.png"] override func viewDidLoad() { super.viewDidLoad() // Uncomment the following line to preserve selection between presentations // self.clearsSelectionOnViewWillAppear = false // Uncomment the following line to display an Edit button in the navigation bar for this view controller. // 편집 버튼(Edit) 만들기(위치는 right, left 중) self.navigationItem.leftBarButtonItem = self.editButtonItem } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } // MARK: - Table view data source override func numberOfSections(in tableView: UITableView) -> Int { // #warning Incomplete implementation, return the number of sections return 1 } // 열의 개수 = 동적이어야 함 override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { // #warning Incomplete implementation, return the number of rows return todoArray.count } // cell 크기 : 테이블 뷰 한 row 크기 // reuseIdentifier의 값은 스토리보드상의 테이블 셀 네임 : attribute의 reuseName override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "ToDoCell", for: indexPath) // 기본 내장 셀에 내장된 imageView, textLabel, 셀의 attribute안의 style참고 cell.textLabel?.text = todoArray[indexPath.row] // cell.detailTextLabel?.text = "Detail" style : subtitle일 때 cell.imageView?.image = UIImage(named: iconArray[indexPath.row]) return cell } // Override to support conditional editing of the table view. override func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool { // Return false if you do not want the specified item to be editable. return true } // 테이블 뷰 안의 cell을 삭제할 때 발생하는 함수 (Edit버튼 클릭시 좌측에 생성) override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) { if editingStyle == .delete { todoArray.remove(at: indexPath.row) iconArray.remove(at: indexPath.row) tableView.deleteRows(at: [indexPath], with: .fade) } else if editingStyle == .insert { // Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view } } // 테이블 뷰 안의 cell을 위 아래로 이동할 때 발생하는 함수 (Edit버튼 클릭시 우측에 생성) override func tableView(_ tableView: UITableView, moveRowAt fromIndexPath: IndexPath, to: IndexPath) { let itemToMove = todoArray[fromIndexPath.row] let iconToMove = iconArray[fromIndexPath.row] todoArray.remove(at: fromIndexPath.row) iconArray.remove(at: fromIndexPath.row) todoArray.insert(itemToMove, at: to.row) iconArray.insert(iconToMove, at: to.row) } // Override to support conditional rearranging of the table view. override func tableView(_ tableView: UITableView, canMoveRowAt indexPath: IndexPath) -> Bool { // Return false if you do not want the item to be re-orderable. return true } // MARK: - Navigation override func prepare(for segue: UIStoryboardSegue, sender: Any?) { let detailVC = segue.destination as? DetailViewController detailVC?.toDoText = ((sender as! UITableViewCell).textLabel?.text)! } // edit버튼 클릭시 나오는 - 버튼 클릭시 기본적으로 delete버튼이 나오는데 이 부분의 문자열을 변경하기 위한 함수, override써야 함(테이블 뷰는 딜리게이트 데이터소스가 미리 선언되어있어 다 정의되어있는 함수이므로 @available(iOS 3.0, *) override public func tableView(_ tableView: UITableView, titleForDeleteConfirmationButtonForRowAt indexPath: IndexPath) -> String?{ return "삭제하기" } }
4. 테이블 뷰 : 커스터마이징, TableViewController가 아닌 일반 뷰 안에 TableView 컨트롤을 넣고 할 경우
import UIKit // 일반 뷰 컨트롤러에 상속을 받았기 때문에 데이터소스, 딜리게이트 선언 필수 class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate { var titleArray = ["알포인트", "셜록", "베를린"] var pointArray = [9.1, 9.2, 8.0] @IBOutlet weak var movieTableView: UITableView! override func viewDidLoad() { super.viewDidLoad() movieTableView.dataSource = self movieTableView.delegate = self } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } @available(iOS 2.0, *) public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int{ return titleArray.count } @available(iOS 2.0, *) public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell{ /* let cell = tableView.dequeueReusableCell(withIdentifier: "MovieCell") // tag값을 이용하여 cell내(하위)의 컨트롤들을 가져올 수 있음, 다른 방법(권장) : MovieCell의 클래스 연결된 MoviewTableViewCell.swift 참고 let imageView = cell?.viewWithTag(1) as? UIImageView imageView?.image = UIImage(named: String(format: "%d.jpg", indexPath.row+1)) let titleLabel = cell?.viewWithTag(2) as? UILabel titleLabel?.text = titleArray[indexPath.row] let pointLabel = cell?.viewWithTag(3) as? UILabel pointLabel?.text = String(pointArray[indexPath.row]) return cell! */ // tag없이 하위 컨트롤 가져오기 let cell = tableView.dequeueReusableCell(withIdentifier: "MovieCell") as! MoviewTableViewCell cell.posterImageView.image = UIImage(named: String(format: "%d.jpg", indexPath.row+1)) cell.titleLabel.text = titleArray[indexPath.row] cell.pointLabel.text = String(pointArray[indexPath.row]) return cell } }
- 태그 값 없이 컨트롤을 가져오려면 테이블 뷰 내의 cell이 상속받는 UITableViewCell클래스를 하나 생성하여 그 클래스를 상속받도록 함, 아래의 예는 MoviewTableViewCell이란 이름으로 클래스를 생성한 것(Moview는 오타)
import UIKit class MoviewTableViewCell: UITableViewCell { @IBOutlet weak var posterImageView: UIImageView! @IBOutlet weak var titleLabel: UILabel! @IBOutlet weak var pointLabel: UILabel! override func awakeFromNib() { super.awakeFromNib() // Initialization code } override func setSelected(_ selected: Bool, animated: Bool) { super.setSelected(selected, animated: animated) // Configure the view for the selected state } }
- 테이블 뷰 위 공백제거하려면 ViewController의 Attribute Inspector -> Adjust Scroll View insets 체크 해제
- 영화 제목이 길어 ...로 나오는 것을 방지하려면 label의 lines(Attribute Inspector)을 0으로
- 추가 페이지 등록 시엔? : ViewController의 배열(titleArray, pointArray)에 append하도록 함(프로토콜, 딜리게이트를 선언)
5. 테이블 뷰 : 영화 DB API(http://www.kmdb.or.kr/)이용하여 XML Parsing -> Table View (내장 테이블 뷰 컨트롤러 사용)
import UIKit class MovieTableViewController: UITableViewController, XMLParserDelegate { var parser = XMLParser() // XML 파싱 객체 var curElement = "" // 현재 XML Element var movieInfoDicArray = [[String:String]] () // Dictionary 배열 == [Dictionary], Array > var movieInfoDic = [String:String]() // Dictionary 객체 var pubTitle = "" // 영화 제목 var contents = "" // 영화 내용 var imageURL = "" // 영화 이미지 URL override func viewDidLoad() { super.viewDidLoad() requestMoveInfoList() } func requestMoveInfoList(){ guard let urlToSend = URL(string: "http://api.koreafilm.or.kr/openapi-data2/service/api105/getOpenDataList") else { return } parser = XMLParser(contentsOf: urlToSend)! parser.delegate = self parser.parse() } // parser가 시작 태그를 만나면 호출되는 함수 public func parser(_ parser: XMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String] = [:]){ curElement = elementName if elementName == "item"{ // 시작 태그 = item : 초기화 movieInfoDic = [String:String]() pubTitle = "" contents = "" imageURL = "" } } // parser가 닫는 태그를 만나면 호출되는 함수 public func parser(_ parser: XMLParser, didEndElement elementName: String, namespaceURI: String?, qualifiedName qName: String?){ if elementName == "item" { if contents.isEmpty == false{ movieInfoDic["contents"] = contents } if pubTitle.isEmpty == false{ movieInfoDic["pubtitle"] = pubTitle } if imageURL.isEmpty == false{ movieInfoDic["imageurl"] = imageURL } movieInfoDicArray.append(movieInfoDic) print(movieInfoDicArray.count) } } // 현재 파서가 가리키는 태그에 담겨 있는 문자열을 얻는 함수 public func parser(_ parser: XMLParser, foundCharacters string: String){ if curElement == "contents" { contents += string } else if curElement == "imageurl" { imageURL += string } else if curElement == "pubtitle" { pubTitle += string } } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } // MARK: - Table view data source override func numberOfSections(in tableView: UITableView) -> Int { // #warning Incomplete implementation, return the number of sections return 1 } override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { // #warning Incomplete implementation, return the number of rows return movieInfoDicArray.count } // 테이블 뷰 셀 데이터 설정 override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "MovieCell", for: indexPath) // 기본 내장 셀에 내장된 imageView, textLabel, 셀의 attribute안의 style참고 cell.textLabel?.text = movieInfoDicArray[indexPath.row]["pubtitle"] return cell } }
6. JSON PARSING : 기본
import UIKit class JSONParser{ func parseJsonData(data: Data?) -> Dictionary?{ // jsonObject란 함수가 throw로 되어있기에 do catch do { // Dict = String이 key 값, AnyObject가 value 값 if let json = try JSONSerialization.jsonObject(with: data!, options: .allowFragments) as? [String: AnyObject]{ return json } else { print("JSON PARSING ERROR") } } catch { print("JSON PARSING ERROR") } return nil } } class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() // 쌍따옴표 앞에 \써줘야 "" 안에서 인식 let jsonString = "{\"number\":20, \"name\":\"gyeom\"}" let parser = JSONParser() if let infoDic = parser.parseJsonData(data: jsonString.data(using: .utf8)), let number = infoDic["number"], let name = infoDic["name"]{ print("number : \(number), name : \(name)") } } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } }
'iOS (교육)' 카테고리의 다른 글
[SWIFT] 마지막 : 스위프트 기본 앱 (0) | 2017.05.13 |
---|---|
[SWIFT] 6일차 : 스위프트 기본 앱 (0) | 2017.04.29 |
[SWIFT] 4일차 : 스위프트 기본 앱 (0) | 2017.04.08 |
[SWIFT] 3일차 : 스위프트 기본 앱 (3) | 2017.04.01 |
[SWIFT] 2일차 : 스위프트 기본 앱 (0) | 2017.03.25 |