Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

연락처 관리 앱 [STEP3] JaeHyeok, Dora #43

Open
wants to merge 4 commits into
base: 2_JaeHyeok
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="22154" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="aJa-gv-N0j">
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="21701" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="aJa-gv-N0j">
<device id="retina6_12" orientation="portrait" appearance="light"/>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="22130"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="21678"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="System colors in document resources" minToolsVersion="11.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
Expand All @@ -18,7 +18,7 @@
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="28" estimatedSectionHeaderHeight="-1" sectionFooterHeight="28" estimatedSectionFooterHeight="-1" translatesAutoresizingMaskIntoConstraints="NO" id="FJ5-JD-ClQ">
<rect key="frame" x="0.0" y="103" width="393" height="715"/>
<rect key="frame" x="0.0" y="159" width="393" height="659"/>
<prototypes>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" accessoryType="disclosureIndicator" indentationWidth="10" reuseIdentifier="cell" textLabel="DzA-lk-glz" detailTextLabel="QmC-Bz-ATn" style="IBUITableViewCellStyleSubtitle" id="God-iG-pJX">
<rect key="frame" x="0.0" y="50" width="393" height="43.666667938232422"/>
Expand Down Expand Up @@ -46,12 +46,24 @@
</tableViewCell>
</prototypes>
</tableView>
<searchBar contentMode="redraw" id="9NH-GT-7Ce">
<rect key="frame" x="0.0" y="103" width="393" height="56"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/>
<textInputTraits key="textInputTraits"/>
<scopeButtonTitles>
<string>Title</string>
<string>Title</string>
</scopeButtonTitles>
<connections>
<outlet property="delegate" destination="BYZ-38-t0r" id="G2M-Ur-dci"/>
</connections>
</searchBar>
</subviews>
<viewLayoutGuide key="safeArea" id="6Tk-OE-BBY"/>
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
<constraints>
<constraint firstItem="FJ5-JD-ClQ" firstAttribute="leading" secondItem="6Tk-OE-BBY" secondAttribute="leading" id="9Hf-DD-Aiu"/>
<constraint firstItem="FJ5-JD-ClQ" firstAttribute="top" secondItem="6Tk-OE-BBY" secondAttribute="top" id="T54-fx-1zM"/>
<constraint firstItem="FJ5-JD-ClQ" firstAttribute="top" secondItem="9NH-GT-7Ce" secondAttribute="bottom" id="T54-fx-1zM"/>
<constraint firstItem="FJ5-JD-ClQ" firstAttribute="bottom" secondItem="6Tk-OE-BBY" secondAttribute="bottom" id="Y3v-Cv-e1a"/>
<constraint firstItem="FJ5-JD-ClQ" firstAttribute="trailing" secondItem="6Tk-OE-BBY" secondAttribute="trailing" id="hFP-Qf-1JN"/>
</constraints>
Expand All @@ -64,13 +76,14 @@
</barButtonItem>
</navigationItem>
<connections>
<outlet property="SearchBar" destination="9NH-GT-7Ce" id="EOd-v6-OE2"/>
<outlet property="tableView" destination="FJ5-JD-ClQ" id="r24-Ng-Nb2"/>
<segue destination="bIj-Df-MAO" kind="presentation" id="MME-fS-GWj"/>
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="65" y="-34"/>
<point key="canvasLocation" x="64.885496183206101" y="-34.507042253521128"/>
</scene>
<!--New Contact View Controller-->
<scene sceneID="0I6-8d-fal">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,39 +9,70 @@ import Foundation

class AddressBook {

private var contacts: [[Contact]] = Array(repeating: [], count: 27)
private var contactsForDisplay: [[Contact]] = [[Contact]]()

func getFirstLetterIndex(_ name: String) -> Int {
let firstLetter = Array(name)[0].uppercased()
let index = firstLetter.unicodeScalars.map { Int($0.value)}[0]
return index >= 65 && index <= 90 ? Int(index - 65) : 26
}
private var contacts = [Contact]()
private var filteredContacts: [Contact]?
private var searchText: String?
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

지금처럼 searchText 프로퍼티를 검색 텍스트로 사용하는 것도 좋은 방법이라고 생각합니다🙂


func addContact(_ newContact: Contact) {
let index = getFirstLetterIndex(newContact.name)
contacts[index].append(newContact)
contacts[index].sort(by: {$0.name < $1.name})
contacts.append(newContact)
contacts.sort(by: {$0.name < $1.name})
}

func deleteContact(_ section: Int, _ row: Int) {
contacts[section].remove(at: row)
func deleteContact(_ row: Int) {
contacts.remove(at: row)
}

func changeContact(_ section: Int, _ row: Int, _ changedContact: Contact) {
contacts[section][row] = changedContact
func changeContact(_ row: Int, _ changedContact: Contact) {
contacts[row] = changedContact
}

func showContact(_ section: Int, _ row: Int) -> Contact {
return contactsForDisplay[section][row]
func showContact(_ row: Int) -> Contact {
guard let input = searchText, let filtered = filteredContacts else {
return contacts[row]
}

if filtered.isEmpty && input.isEmpty {
return contacts[row]
}

if !input.isEmpty {
return filtered[row]
}

return contacts[row]
}

func getSectionSize() -> Int {
contactsForDisplay = contacts.filter{ !$0.isEmpty }
return contactsForDisplay.count
func getRowSize() -> Int {

guard let input = searchText, let filtered = filteredContacts else {
return contacts.count
}

if filtered.isEmpty && input.isEmpty {
return contacts.count
}

if !input.isEmpty {
return filtered.count
}

return contacts.count
}

func getRowSize(_ section: Int) -> Int {
return contactsForDisplay[section].count
func searchContact(_ input: String) {
searchText = input
filteredContacts = []

for contact in contacts {
if contact.name.lowercased().contains(input.lowercased()) {
filteredContacts?.append(contact)
}
}

for contact in contacts {
if contact.phoneNumber.replacingOccurrences(of: "-", with: "").contains(input.replacingOccurrences(of: "-", with: "")){
filteredContacts?.append(contact)
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,47 +26,47 @@ class NewContactViewController: UIViewController {
phoneNumberTextField.delegate = self
}

func navigationSetting() {
private func navigationSetting() {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

private 키워드를 사용해보셨네요.👍

navigationBar.isTranslucent = false
navigationBar.shadowImage = UIImage()
}

func keyboardSetting() {
private func keyboardSetting() {
nameTextField.keyboardType = .namePhonePad
ageTextField.keyboardType = .numberPad
phoneNumberTextField.keyboardType = .phonePad
}
}

extension NewContactViewController {
@IBAction func tappedCancelButton(_ sender: UIButton) {
cancelAlert()
@IBAction private func tappedCancelButton(_ sender: UIButton) {
showCancelAlert()
}

@IBAction func tappedSaveButton(_ sender: UIButton) {
guard let name = nameCheck() else {
@IBAction private func tappedSaveButton(_ sender: UIButton) {
guard let name = checkName() else {
invalidAlert(invalid: nameTextField)
return
}
guard let age = ageCheck() else {
guard let age = checkAge() else {
invalidAlert(invalid: ageTextField)
return
}
guard let number = numberCheck() else {
guard let number = checkNumber() else {
invalidAlert(invalid: phoneNumberTextField)
return
}
saveAlert(Contact(name: name, phoneNumber: number, age: age))
}

func cancelAlert() {
private func showCancelAlert() {
let alert = UIAlertController(title: title, message: "정말 취소하겠습니까?", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "예", style: .destructive, handler: { _ in self.dismiss(animated: true)}))
alert.addAction(UIAlertAction(title: "아니오", style: .default, handler: nil))
present(alert, animated: true)
}

func saveAlert(_ contact: Contact) {
private func showSaveAlert(_ contact: Contact) {
let text: String = "이름: \(contact.name), \n 나이: \(contact.age), \n 연락처: \(contact.phoneNumber) \n 저장하시겠습니까?"
let alert = UIAlertController(title: title, message: text, preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "예", style: .default, handler: { _ in
Expand All @@ -76,28 +76,28 @@ extension NewContactViewController {
present(alert, animated: true)
}

func nameCheck() -> String? {
private func checkName() -> String? {
guard let name = nameTextField.text else {
return nil
}
return name == "" ? nil : name.components(separatedBy: " ").joined()
return name.isEmpty ? nil : name.components(separatedBy: " ").joined()
}

func ageCheck() -> Int? {
private func checkAge() -> Int? {
guard let ageText = ageTextField.text, let age = Int(ageText) else {
return nil
}
return age
}

func numberCheck() -> String? {
private func checkNumber() -> String? {
guard let number = phoneNumberTextField.text else {
return nil
}
return number.count >= 11 && number.filter { $0 == "-" }.count == 2 ? number : nil
}

func invalidAlert(invalid: UITextField) {
private func invalidAlert(invalid: UITextField) {
var text: String

switch invalid {
Expand All @@ -123,7 +123,6 @@ extension NewContactViewController: UITextFieldDelegate {

if range.location == 2 && number.last != "-" {
number.insert("-", at: number.index(number.startIndex, offsetBy: 2))
print(number.count)
}

if range.location == 6 && number.last != "-" {
Expand Down
35 changes: 24 additions & 11 deletions ios-contact-manager-ui/ios-contact-manager-ui/ViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,9 @@ import UIKit
class ViewController: UIViewController {

@IBOutlet weak var tableView: UITableView!
@IBOutlet weak var searchBar: UISearchBar!

var cellIdentifier: String = "cell"
private let cellIdentifier: String = "cell"
var addressBook: AddressBook = AddressBook()

override func viewDidLoad() {
Expand All @@ -20,33 +21,38 @@ class ViewController: UIViewController {
initialSetting()
}

func initialSetting() {
private func initialSetting() {
self.tableView.dataSource = self
self.searchBar.delegate = self
}
}

extension ViewController: UITableViewDataSource {

func numberOfSections(in tableView: UITableView) -> Int {
addressBook.getSectionSize()
}

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
addressBook.getRowSize(section)
addressBook.getRowSize()
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell: UITableViewCell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath)
let contactData: Contact = addressBook.showContact(indexPath.section, indexPath.row)

let contactData: Contact = addressBook.showContact( indexPath.row)
cell.textLabel?.text = contactData.name + "(\(contactData.age))"
cell.detailTextLabel?.text = contactData.phoneNumber
return cell
}

func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
addressBook.deleteContact(indexPath.row)
defer {
tableView.deleteRows(at: [indexPath], with: .automatic)
}
}
}
}

extension ViewController {
@IBAction func TappedAddButton(_ sender: UIBarButtonItem) {
@IBAction private func TappedAddButton(_ sender: UIBarButtonItem) {
guard let newContactViewController = storyboard?.instantiateViewController(withIdentifier: "NewContactViewController") as? NewContactViewController else { return }
newContactViewController.delegate = self
self.present(newContactViewController, animated: true)
Expand All @@ -56,6 +62,13 @@ extension ViewController {
extension ViewController: SendDelegate {
func sendContact(newContact: Contact) {
self.addressBook.addContact(newContact)
self.tableView.reloadData()
tableView.reloadData()
}
}

extension ViewController: UISearchBarDelegate {
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
addressBook.searchContact(searchText)
tableView.reloadData()
}
}