32YB SOPT/iOS 세미나

[SOPT] iOS_1주차_정규세미나 (Xcode사용법, iOS기초, 화면 전환, 데이터 전달 기초)

신_이나 2023. 6. 27. 06:05

23.04.01 SOPT iOS 1주차 정규세미나 내용

 

 

1. iOS 란?

 iOS란 애플의 모바일 운영체제를 말하며, iPhone 을 위한 OS 라는 의미를 갖는다. iOS 는 macOS 의 요소인 코코아, 코어 애니메이션 등의 애플리케이션 프레임워크를 포함하고 있다. 그 중에서도 Cocoa Framework 는 맥용 애플리케이션을 만들 때 사용하는 프레임워크다. 따라서 아이폰 개발을 할 때 Cocoa Framework 를 이용하여 개발을 할 수 있게 된다. 

 

 

2. Framework 와 Library

 UIKit란 iOS, iPadOS 또는 tvOS 앱을 위한 그래픽 이벤트 기반 사용자 인터페이스를 구성하고 관리한다. 사용자 인터페이스를 구현하고 관리하는 기능을 제공한다는 것이다. 

 

Foundation 은 원시 데이터 타입, 컬렉션 타입 및 운영체제 서비스를 사용해 애플리케이션의 기본적 기능을 수행하는 Framework 다. 

 

이때 UIKit 와 Foundation 은 Framework 인데, Framework 는 원하는 기능 구현에 집중하여 개발할 수 있도록 일정한 형태와 필요한 기능을 갖추고 있는 뼈대를 말한다.(ex, CoreData, Mapkit)

Library 는 소프트웨어를 개발할 때 컴퓨터 프로그램이 사용하는 비휘발성 자원의 모임이다. 따라서 특정 기능을 모아둔 코드 함수들의 집합을 의미한다. (ex, SnapKit, Then, Moya, Realm)

 

 

3. 실습 시작 시 세팅

Storyboard 제거 및 시작 화면을 변경해야 한다.

1. Launch Screen File 제거

2. Storyboard Name 제거

3. SceneDelegate 에서 rootViewController 를 변경하여 시작 화면을 변경

//3번에 해당하는 코드

import UIKit

class SceneDelegate: UIResponder, UIWindowSceneDelegate {
    
    var window: UIWindow?
    
    func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
        
		// 1.
        guard let windowScene = (scene as? UIWindowScene) else { return }
    // 2. 
        self.window = UIWindow(windowScene: windowScene)
    // 3.
        let navigationController = UINavigationController(rootViewController: ViewController())
        self.window?.rootViewController = navigationController
    // 4.
        self.window?.makeKeyAndVisible()
	}
}

 

 

 

4. UIComponent

UILabel 을 뷰에 띄우고 간단한 AutoLayout 을 잡는 실습을 해보자!

SnapKit 이라는 Library 를 사용할 수 있지만 우선은 하나하나 잡아줄 것이다.

import UIKit

final class ViewController: UIViewController {
     
    private let nameLabel: UILabel = {
        let label = UILabel()
        label.text = "솝트에 오신 여러분 환영합니다!"
        return label
    }()

    override func viewDidLoad() {
        super.viewDidLoad()

        setStyle()
        setLayout()
    }
}

private extension ViewController {
    
    func setStyle() {
        
        view.backgroundColor = .white
    }
    
    func setLayout() {
        
        nameLabel.translatesAutoresizingMaskIntoConstraints = false
        
        view.addSubview(nameLabel)
        
        NSLayoutConstraint.activate([nameLabel.topAnchor.constraint(equalTo: view.topAnchor, constant: 300),
                                     nameLabel.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 50)])
    }
}

위 코드를 입력하면 아래와 같은 이미지가 뜬다.

 

짜잔! 그럼 여기서 문제, 모든 기기가 다 위와 같이 나올까? 떙! 기기마다 해상도가 다르기 때문에 같은 제약 조건을 주더라도 상대적인 위치가 다를 수 있다. 따라서 H.I.G 을 통해 UiComponent 를 설정해보도록 하자.

 

 

4-1. H.I.G 을 통한 UIComponent

 HIG 는 양이 방대하여 세미나에서 전부 다루기가 어렵다. 따라서 가장 많이 쓰이는 것 위주로 세미나를 진행하신다고 하셨다! 우선 H.I.G 란 Human Interface Guideline 의 약자로 HIG에는 모든 Apple 플랫폼을 위한 훌륭한 경험을 디자인하는 데 도움이 되는 지침과 모범 사례가 포함되어 있다. 여러 섹션으로 구성되어 있는데 Platforms, Foundations, Patterns, Components, Inputs, Technologies 등과 같이 나누어져 있고 1주차에서는 Compnents 부분을 살펴보았다. 

 

- UILabel

Label을 수정할 수는 없지만, 복사는 가능하다.

가장 중요한 점은 Label을 통해 사용자가 어떤 작업을 수행하도록 가이드 한다는 것이다.

1. var font: UIFont! -> 텍스트의 글꼴
label.font = .systemFont(ofSize: 14)

2. var textColor: UIColor! -> 텍스트의 색상
label.textColor = UIColor.blue

3. var textAlignment: NSTextAligment! -> 텍스트를 정렬하는 방법
label.textAlignment = .center

 

- UIButton

버튼은 즉시 알아볼 수 있고 이해하기 쉬워야 한다. 그에 따라 사람들이 쉽게 선택할 수 있는 버튼을 만들어야 하는데 보통 스크린에서 손가락 끝으로도 사용할 수 있게끔 최소 44 x 44 px로 만든다.

추후에 개발을 하게 될 때, 서비스 브랜딩에 따라 커스텀해서 많이 사용한다.

 

1. func setTitle(String?,
   for: UIControl.State)
 -> 버튼의 Title
button.setTitle("32기 아요 짱!", for: .normal)

2. var titleLabel: UILabel? { get } -> 버튼 Title의 다양한 속성들을 정의
button.titleLabel?.font = .systemFont(ofSize: 14)

3. func setTitleColor(
    _ color: UIColor?,
    for state: UIControl.State
) -> 버튼 Title의 색상을 변경
button.setTitleColor(.yellow, for: .normal)

 

-UITextField

'이건 검색할 수 있게 만들어놓은 텍스트필드이다!' 라는 목적을 전달하는 데 도움이 되도록 텍스트필드에 적절한 힌트를 주어야 한다. (예를 들어, ~를 검색해보세요! 등) 이미지와 버튼을 사용하여 텍스트필드에 명확성과 기능을 제공해야 한다. 예를 들어 텍스트 전체를 한 번에 지울 수 있는 버튼을 x표 모양으로 하여 텍스트필드 끝 쪽에 배치하는 것처럼 말이다.

1. var placeholder: String? { get set } 
-> 텍스트필드 placeholder의 텍스트를 지정
textField.placeholder = "32기 아요 짱!"

2. var clearButtonMode: UITextField.ViewMode { get set }
-> 텍스트필드의 내용이 있을 때 텍스트필드 오른쪽에 표시되어 사용자가 텍스트를 빠르게 제거할 수 있는 방법을 제공
-> 한마디로 x버튼!
textField.clearButtonMode = .always

 

위 코드들을 착착 작성하여 빌드시킨다면

이렇게 귀여운 컴포넌트들이 뿅뿅하고 생겨난다. 처음엔 안귀여웠는데 다시 보니까 귀엽네 ㅎㅋ

물론 작성하고 버튼을 누른다고 해서 달라지는 것은 없다 하하!

 

계층을 보고싶다면 네모 층층이 쌓인 아이콘을 클릭하여 볼 수 있다. 아이콘이 덮이진 않았는지 등등 확인할 때 아주 유용하다. 위의 계층구조를 확인하면 UIView 안에 UILabel(), UIButton() 가 쌓여있는 것을 볼 수 있는데 UIView 란 화면의 직사각형 영역에 대한 컨텐츠를 관리하는 객체다. 

 

 

 

5. 생애주기

두둥 생애주기다. 처음에 보았을 땐 그냥 그렇구나~ 했는데 코드를 슬슬 작성하기 시작하는 요즘, 정말 중요하구나를 다시 한 번 느낀다! 

1주차 과제에서 정리를 해두긴 했지만 팟장님이 정리해주신 텍스트로 다시 한 번 더 공부해보자!

1. viewDidLoad
    - ViewController.swift 파일을 만들면 자동으로 뭐가 만들어져 있지 않나요?!
    - 뷰 계층이 최초 메모리에 로드된 후에 호출이 되는 메서드입니다!
    - 뷰의 로딩이 완료 되었을 때 시스템에 의해 자동으로 호출이 되기 때문에 
    리소스를 초기화하거나 초기 화면을 구성하는 용도로 주로 사용을 합니다!
    - 화면이 만들어질 때 처음 한 번만 실행이 됩니다!
2. viewWillAppear
    - viewDidLoad 다음에 실행이 되는 메서드입니다.
    - viewWillAppear은 말 그대로 “뷰가 이제 나타날거야!” 라는 의미를 가집니다.
    - 다만 viewDidLoad와 다른 점은 다른 뷰에서 다시 돌아오는 상황에서 viewWillAppear부터 실행이 됩니다.
3. viewDidAppear
    - 뷰가 사라지기 직전에 호출되는 메서드입니다.
    - 주로 애니메이션에 관한 코드를 작성합니다.
4. viewWillDisappear
    - 뷰가 계층에서 사라지기 직전에 호출되는 메서드입니다.
    - 뷰가 생성된 뒤 발생한 변화를 이전 상태로 되돌리기 좋은 시점입니다.
5. viewDidDisappear
    - 뷰가 계층에서 사라진 후 호출되는 메서드입니다.
    - 시간이 오래 걸리는 작업은 권장되지 않습니다.

> 그렇다면 위 사진의 화살표는 무엇을 의미하는 걸까요?
 
- 메모리에 뷰가 있다면 viewWillAppear부터 호출이 됩니다.
- 메모리에 뷰가 없다면 loadView부터 시작하게 됩니다.

> 그렇다면 loadView는 무엇인가요?

- loadView는 컨트롤러가 관리하는 뷰를 만드는 역할을 합니다.
- loadView가 뷰를 만들고, 메모리에 올린 후에 viewDidLoad가 호출됩니다.

👏🏻👏🏻👏🏻👏🏻👏🏻👏🏻👏🏻 특히 애니메이션 공부할 때 요 생애주기가 많이 중요했다. 그리고 팟장님이 코드를 많이 짜다보면 나중엔 시작이 뷰를 구상하는 것보다 데이터 흐름을 더 먼저 보게 된다고 하시는데 그때 중요한 것이 이 생애주기 아닐까?

 

 

 

6. 화면전환

화면 전환을 해주기 위해선 현재 view 외에 전환하여 이동할 view 를 만들어주어야 한다.

func presentToSecondViewController() {
        
        let secondViewController = SecondViewController_1st_Seminar()
        secondViewController.modalPresentationStyle = .fullScreen
        self.present(secondViewController, animated: true)
}
    
@objc
func presentButtonTapped() {
        
        presentToSecondViewController()
}

...

private lazy var presentButton: UIButton = {
        let button = UIButton()
        button.setTitle("present!", for: .normal)
        button.backgroundColor = .yellow
        button.setTitleColor(.blue, for: .normal)
        
        // 새롭게 추가 !!!!!!!!!!!!
        button.addTarget(self,
                         action: #selector(presentButtonTapped),
                         for: .touchUpInside)
        return button
}()

이때 사용한 코드를 이해해보자

@objc 란, 

 

  • Swift를 사용한 코드를 Objective-C 코드와 상호작용 시키기 위해 쓰는 키워드다.
  • Swift를 사용한 코드에서 class나 method에 이 키워드를 붙이면 Objective-C와 Swift 코드에서 사용할 수 있게 된다.

#selector 란,

  • Objective-C의 유산으로, @selector({methodName})으로 사용하다가 이제는 #selector 를 주로 쓴다.
  • 함수를 직접 지정해서 실행할 때 사용하며, 컴파일 시가 아닌 런타임에서 함수가 실행되는 동적 바인딩의 형태를 가진다.
  • 이 #selector에 전달할 메소드를 작성할 때는 Objective-C와의 호환성을 위해 반드시 함수에 @objc 코드를 붙여준다

addTarget(_:action:for:)

  • controlEvent가 발생하는 했을 때, 실행 주체인 target과 함수를 연결해주는 함수다.

 

 

present 버튼 뿐만 아니라 push 버튼과 back 버튼도 동일한 방식으로 코드를 추가하여 위와 같은 view 를 구현하였다.

present 은 modalPresentationStyle 로 받았기 때문에 팝업처럼 위에 뜨는 형식으로 화면이 전환되었고, push 버튼은 화면 자체가 다음 페이지로 넘어가도록 하여 아래와 같은 코드를 추가하였다. 

func pushToSecondViewController() {
        
        let secondViewController = SecondViewController()
        self.navigationController?.pushViewController(secondViewController, animated: true)
}

 

 

7. 데이터 전달

그럼 텍스트필드에서 작성한 이름을 다음 화면에도 전달하고 싶다면 어떻게 해야 할까?

데이터를 묶어주어야 한다!

그러기 위해선 SecondViewController 에 넘어온 데이터를 묶어주는 코드가 필요하다.

var name: String?

func dataBind() {
            nameLabel.text = name
}

name 이라는 변수를 선언하고 앞선 view 에서 받아온 데이터를 name 에 저장하여 nameLabel.text 에 넣어주었다. 넣어준건 알겠는데 '앞선 view 에서 받아온 데이터를 name 에 저장' 요건 어디서 했는데? 바로 앞선 ViewController 에서!

 

func pushToSecondViewController() {

        ⭐️⭐️
        guard let name = nameTextField.text else { return }
        let secondViewController = SecondViewController()
        secondViewController.name = name
        ⭐️⭐️
        
        self.navigationController?.pushViewController(secondViewController, animated: true)
    }

name 은 String 이기 떄문에 Optional 처리 해주기 위하여 guard let 을 작성하였다.  가 아니라 nullable 하기 때문에 옵셔널 바인딩을 넣어주는 것이다. (라고 표현해야 한다고 익범오빠가 그랬다) 그리고 난 뒤 textField 에 작성한 이름을 name 이라는 변수에 저장하였고 이를 다시 SecondViewController 에 선언한 name 에 저장해주었다.

 

push에만 dataBind 코드를 추가하였기 때문에 push 버튼을 눌렀을 때는 데이터가 잘 전송되지만 present 에서는 전송되지 않는 것을 알 수 있다.