0%

COCOAPODS-Carthage 설치

1. Cocoapods설치 (터미널을 통해서)

1
$ brew update && brew install carthage
  • 코코아 팟 과는 다르게, 깃헙에 직접 접근해서 사용하는 것임
    • 코코아 팟은 코코아 팟에 등록 된 라이브러리만 사용 가능
    • 코드도 볼 수 없음 바이너리화 되어있어서
    • 대신 이미 빌드가 되어있기 때문에 빌드 시간이 코코아팟보다 짧음

2. 라이브러리를 사용할 프로젝트를 생성 후 터미널에서 해당파일경로로 이동

1
2
3
4
$ vi Cartfile

github "Alamofire/Alamofire"
github "onevcat/Kingfisher"

-> Cartfile을 열어서 사용할 라이브러리 작성 (vi에 걍적어주면됨)

##3. vi를 작성했다면 터미널에서 업데이트

1
2
3
$ carthage update # 전체 업데이트
$ carthage update # platform iOS - iOS Platform 한정
$ carthage update Alamofire # 여러 가지 라이브러리 중 일부만 지정하여 업데이트 할 때
1
Build Phase -> Link Binary With Libraries -> ‘+’버튼 -> ‘Add Other…’ -> ‘Add files’ -> 프로젝트의 폴더에서 ‘Carthage’ 폴더 -> ‘Build’ -> ‘iOS’ -> ‘{filename}.framework’ -> 열기

Link Binary

5. New Run Script Phase

1
2
3
4
5
Build Phases - Run Script - Shell
> /usr/local/bin/carthage copy-frameworks

Build Phases - Run Script - Input Files
> $(SRCROOT)/Carthage/Build/iOS/[Name].framework

New Run Script

6. Import !̆̈!

1
2
3
import Alamofire
// 예시(등록한 라이브러리가 import된다면 성공~~~)
// 코코아팟이랑 다른점은 또다른 프로젝트가 생성이되지 않음~

Cocoapods을 설치해서 라이브러리 사용

  1. 터미널에서 cocoapods설치
1
$ sudo gem install cocoapods
  1. 라이브러리를 사용할 프로젝트를 생성 후 터미널에서 해당파일경로로 이동
1
$ pod init

-> Podfile라는 파일이 자동으로 생성된다

  1. 사용할 라이브러리를 vi로 파일을 열어 작성해준다
1
2
3
4
5
6
7
8
9
10
11
12
13
14
$ vi Podfile

# Uncomment the next line to define a global platform for your project
# platform :ios, '9.0'

target 'CocoaPodsExample' do
# Comment the next line if you don't want to use dynamic frameworks
use_frameworks!

# Pods for CocoaPodsExample
pod 'RAMAnimatedTabBarController' # <- 이부분에 작성!
pod 'SnapKit'

end
  1. 업데이트 및 인스톨 -> .xcworkspace로 새로운 파일이 생성됨
1
2
3
4
5
$ pod repo update
$ pod install
# pod install을 이전에 한 번도 수행한 적이 없을 경우 약 5 ~ 15분 소요

$ open [ProjectName].xcworkspace

library

Animated-tab-bar Library사용

animated-tab-bar

Installation

Just add the RAMAnimatedTabBarController folder to your project.

or use CocoaPods with Podfile:

1
pod 'RAMAnimatedTabBarController'

-> 코코아 팟으로 라이브러리 설치!

Usage

Usage

1
2
3
4
5
6
7
8
9
10
11
12
1. 스토리보드에 새 UITabBarController를 만들어라.

2. 스토리보드에서 UITabBarController의 클래스를 RAMAnimedTabBarController로 설정.

3. 각 UITabBarItem에 대해 클래스를 RAMAnimedTabBarItem으로 설정.

4. 각 RAM에 대한 사용자 지정 이미지 추가AnimedTabBarItem

5. 각 RAMAnimedTabBarItem에 대한 애니메이션 추가:
- NSObject 항목을 ViewController에 끌어다 놓기
- 클래스를 ANIMATION_CLASS로 설정(여기서 ANIMATION_CLASS는 사용하려는 애니메이션의 클래스 이름임)
- RAMAnimedTabBarItem의 아웃렛 애니메이션을 ANIMATION_CLASS 시연 비디오에 연결 5단계

Ram

OOP 기본

  • 객체: 클래스에서 생성된 변수, 클래스에서 파생되어 나오는 것, 혼자서 존재하는것은 의미가 없다. 그 객체와 다른 객체들간의 상호작용이 있을때 의미가 있다.

  • 객체지향 프로그래밍: 객체들을 설정하고 그 객체들간의 관계를 설계하는 것

    • 내가 필요한 객체가 뭔지를 설계 하는 것
    • 각 객체들간의 어떤형태로 상호작용을 하도록 만들것인지
    1
    "많은 개체들이 공통된 명칭을  가질 때 그것들은 언제나  또 하나의 이데아, 즉 형상을 갖는다. 가령 침대는 무수히 많지만 침대의 이데아, 즉 그 형상은 오직 하나이다. 여러가지 개개의 침대는 실재가 아니며 오직 그 이데아의 모사(模寫)에 의해 만들어졌을 뿐이다.”  - 플라톤
  • 똑같은 이데아 = 틀, 클래스

  • 이데아에 의해 만들어지게되는 실제 물건이나 형상 = 객체, 오브젝트

Class, Object

[ Class ]

  • 추상 (abstract) , 표현 대상에 대한 이데아(형상)

  • 이상적인 존재 (이미지, 설계도, 틀, 설명서)

  • 공통의 특징

  • 강아지라는 공통적인 개념(예시)

    [ Object ]

  • 실체(instance) , 추상을 실체화한 대상

  • 이데아의 모사

  • 개별 속성

  • 서로 다른 각각의 강아지들(예시)

Class

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
let x = 5             // struct, Stack에 저장
let y = User() // class, Heap에 저장
let z = User() // class, Heap에 저장

x y z
[Stack] | 5 | 0x5F17 | 0x2C90 |
// Stack -> 처음부터 만들어지는 시점, 크기가 지정되어짐

0x2C90 0x5F16 0x5F17
[Heap] | z's user data | SomeData | y's user data |
// Heap -> 실제데이터는 힙에저장. 참조타입.

--- in Memory ---
값 타입(Value Type) - Stack
참조 타입(Reference Type) - Stack -> Heap

class <#ClassName>: <#SuperClassName>, <#ProtocolName...> {
// SuperClassName: 옵셔널, 상속받지않으면 생략가능
// ProtocolName: 상속받지않으면 생략가능
<#PropertyList>
<#MethodList>
}

let <#objectName> = <#ClassName()> // 변수에 클래스를 상속
objectName.<#propertyName>
objectName.<#functionName()>

Class Initialize(초기화 메서드)

  • 초기화(init)가 불필요한 경우 : 모든 저장 프로퍼티에 초기값이 설정되어 있음
  • 초기화(init)가 필요한 경우 : 저장 프로퍼티 중 하나 이상이 초기값 미설정됨
  • 모든 저장 프로퍼티 (Stored Properties)에 초기값이 설정된 경우 Init 메서드 작성 불필요
  • 객체 생성시 단순히 ClassName() 만으로 생성 가능
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Dog {
let name: String
let color: String

// init메서드를 다양하게 지정해줄 수 있다.
init(name: String) {
// 컬러는 고정되어있는 init
self.name = name
color = "Brown"
}
init(name: String, color: String) {
// 두가지를 바꿀수있는 init
self.name = name
self.color = color
}

func bowwow() {
print("Dog Bowwow!")
}
}

Property

Stored Property(저장 프로퍼티)

  • Class ⭕️ Structure⭕️ Enum ❌
1
2
3
4
5
6
7
8
9
10
11
class StoredProperty {
var width = 0.0
var height = 0.0
}

let stored = StoredProperty()
stored.width = 123
stored.height = 456
stored.width // 123
stored.height // 456
// 저장된 값을 사용

Lazy Stored Property(지연 저장 프로퍼티)

  • 초기값이 인스턴스의 생성이 완료 될 때까지도 알 수 없는 외부 요인에 의존 할 때
  • 초기값이 복잡하거나 계산 비용이 많이 드는 설정을 필요로 할 때
  • 필요한 경우가 제한적일 때
  • Class ⭕️ Structure ⭕️ Enumeration ❌
  • 한번 저장된 값은 직접 변경해주지 않는 이상 바뀌지 않는다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class LazyStoredProperty {
var width = 10.0
var height = 20.0

// 1. 외부 요인이나 다른 설정에 기반
lazy var area = self.width * self.height
// lazy를 붙여주면 초기화가 끝나지 않아도 사용이 가능(area를 호출할때 비로소 만들어지기 때문)

// 2. 계산 비용이 많이 드는 상황
lazy var hardWork = "실행하면 약 10초 이상 걸려야 하는 작업"
// 화면을 띄우는순간 꼭 필요한 작업이 아닌데 lazy가아닌 일반 프로퍼티로 있으면 이작업을 실행후 화면을 띄울수 있기 때문에 사용자가 어떤 버튼을 눌렀을때만 필요한 작업이라면 미리할 필요가없기 때문에 이런상황에서 사용

// 3. 필요한 경우가 제한적인 상황(대부분 else로빠지는데 5% 상황만 true를 사용할때 메모리를 조금이라도 더아끼기 위해 초기화과정도 하지 않고 넘어가기 위해)
func ifStatement() {
if true { // 5%
print(area)
} else { // 95%
print(width)
}
}
}

Computed Property(연산&계산 프로퍼티)

  • 자료를 저장하지 않고 매번 호출할 때마다 새로 계산
  • Class ⭕️ Structure ⭕️ Enumeration ⭕️
1
2
3
4
5
6
7
8
9
10
// Computed Property 사용
var <#variablename>: <#type> {
get {
<#statements>
}
set {
<#variablename> = newValue
}
}
// 읽기전용 get, 쓸때는 set 도 붙임
  • get: 연산프로퍼티를 호출할때 보여지는 구간
  • Set: 연산프로퍼티에 값을 입력했을때 실행되는 구간 / 값을 저장할수 없으므로 저장프로퍼티를 이용한다.
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
32
33
34
35
36
37
38
39
40
41
42
43
class ComputedProperty {
var width = 5.0
var height = 5.0

lazy var lazyArea = width * height
var area: Double { // 연산프로퍼티: 매번 새롭게 계산하기위해
return width * height // 읽기전용은 get생략 가능, 리턴도 생략 가능
}

// Stored + Computed get(read), set(write)
private var _koreanWon = 0.0 // 저장프로포티
var wonToDollar: Double {
get {
return _koreanWon / 1136.5
// 저장프로퍼티의 값을 이용해서 연산을 함
}
set {
_koreanWon = newValue
// set은 값을 저장할 수 없으므로, 저장프로퍼티를 이용한다.
// newValue 값을넣으면 여기로 들어옴. set에 새로들어오는 값을 newValue에 저장.
}
}
}

var computed = ComputedProperty()
computed.area // 25
computed.lazyArea // 25

computed.width = 10
computed.area // 50
computed.lazyArea // 위에서 최초 초기화를 시켰기에 그대로 25

computed.lazyArea = 50.0 // lazy는 호출된 이후엔 직접 값을 변경시켜줘야함
computed.lazyArea // 50

computed.width = 20
computed.height = 20
computed.area // 400
computed.lazyArea // 바꿔준 50으로 나옴

computed.wonToDollar
computed.wonToDollar = 10000
computed.wonToDollar // 만원을 입력시 환율된값이 나오도록 연산프로퍼티를 만듬

Property Observer(프로퍼티 옵저버)

  • Class ⭕️ Structure ⭕️ Enumeration ❌
  • newValue값이 들어오면 변경직전 및 직후 상태를 확인(반환)해 줄 수 있다.
1
2
3
4
5
6
7
8
9
10
11
// 저장프로퍼티 옵저버 사용
var <#variable> name: <#type> = <#value> {
willSet {
<#statements>
// 변수의 값이 바뀌기 직전 호출
}
didSet {
<#statments>
// 변경된 직후 호출
}
}
  • 추가적인 작업을 자동으로 반복해야 할때 그것을 별도로 또다시 만들지 않고 변수만 수정해도 자동으로 반영되도록
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class PropertyObserver {
var height = 0.0
var width = 0.0 {
willSet {
print("willSet :", width, "->", newValue) // width = 0.0, newValue = 123.0
}
didSet {
print("didSet :", oldValue, "->", width) // old = 0.0 , width = 123.0
height = width / 2
}
}
}

var obs = PropertyObserver()
obs.height = 456
obs.height

obs.width = 123
obs.width
/*
willSet : 0.0 -> 123.0
didSet : 0.0 -> 123.0
*/

Type Property(타입 프로퍼티)

  • Shared(공유) / 하나의 타입이자 클래스가 모든것을 공유한다.
  • Lazily Initialized(지연 특성을 지님)
  • Class ⭕️ Structure ⭕️ Enumeration ⭕️
1
2
3
4
5
6
7
// 타입프로퍼티 사용
선언 - static let(var) <#propertyName>: <#Type>
class var <#propertyName>: <#Type> { return <#code> }
사용 - <#TypeName>.<#propertyName>

static: override 불가
class: 클래스에서만 사용 가능하고 computed property 형태로 사용. 서브클래스에서 override 가능
  • static var = 타입 프로포티, 객체를 만들지 않고 클래스에서 바로 .으로 사용가능
  • 어떤 도형을 만들고싶을때 높이를 똑같이 공유하고싶다. 이럴때도 사용이 가능
  • 타입전체가 공유하고자 할것을 만들 때
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class TypeProperty {
static var unit: String = "cm"

var width = 5.0
}

let square = TypeProperty() // 타입을 객체로 만들어서 프로포티에 접근
square.width

let square1 = TypeProperty()
square1.width = 10.0 // width의 값을 바꿔준다
square1.width

TypeProperty.unit
//타입자체에서 프로포티에 접근하는 방식 = 타입 프로포티 // = "cm"
print("\(square.width) \(TypeProperty.unit)") // 5.0 cm
print("\(square1.width) \(TypeProperty.unit)") // 10.0 cm

TypeProperty.unit = "m"
//단위를 전체적으로 바꾸고싶을때 unit자체를 바꿔준다. 모든 객체들이 공통으로 사용해야할 놈을 공유한다.
print("\(square.width) \(TypeProperty.unit)") // 5.0 m
print("\(square1.width) \(TypeProperty.unit)") // 10.0 m

Property 종류 정리

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
class MyClass {
// 저장 프로퍼티
var value1 = 0
// 지연 저장 : 호출했을 때 초기화
lazy var value2 = value1 + 10
// 연산
var value3: Int {
// 읽기
get {
let myValue = 50
return value1 + myValue
}
// 쓰기
set {
let myValue = newValue + 10
value1 = myValue + 20
}
}
// 프로퍼티 옵저버
var label = UILabel()
var text = "" {
willSet {
label.text = newValue
}
didSet {
label.text = text
}
}
var value4: Int = 100 {
willSet {
print("Value4가 \(value4)에서 \(newValue)으로 바뀔 것이다.")
}
didSet {
print("Value4가 \(oldValue)에서 \(value4)으로 바뀌었다.")
}
}
// 타입
static var value5: Int = 15
}
let myclass = MyClass()
myclass.value1 // 읽기
myclass.value1 = 10 // 쓰기
myclass.value2
myclass.value1 = 20
myclass.value2
myclass.value3 = 30
myclass.value1
myclass.value2
myclass.value3
myclass.value4 = 200
myclass.text = "집가고싶다"
MyClass.value5 = 25
MyClass.value5

UIView lifecycle, Present, Full & Card Screen

UIViewController lifecycle

  • init() - 생성
  • viewDidLoad (뷰가 로드됨) -> 초기화작업 / 메모리상에서의 로드 / 뷰가만들어질때 한번만 호출
  • viewWillAppear (뷰가 나타날것) -> 보여지기직전에 호출 / 보여질때마다 호출
  • viewDidAppear (뷰가 나타났다) -> 뷰가 화면에 나타난 직후 / 보여진직후에 호출
  • viewWillDisappear (뷰가 사라질 것이다) -> 뷰가 사라지기 직전
  • viewDidDisappear (뷰가 사라졌다) -> 뷰컨트롤러가 뷰가 제거되었음을 알려줌 / 사라진직후
  • deinit() - 해제

스크린샷 2019-12-07 오후 9.14.46

버튼을 사용해서 다음화면으로 넘어갈때의 뷰생명주기를 확인해보자 ( ios12버전)

  • 첫화면이 뜨자 나타나는 함수
1
2
3
viewDidLoad--[뷰가로드됨]
viewWillAppear--[뷰가나타날것임]
viewDidAppear--[뷰가나타났다]
  • 버튼을 클릭시 나타나는 함수
1
2
3
4
5
6
----------- [ Nextvc viewDidLoad ] ----------

viewWillDisappear--[뷰가사라질것임]
Nextvc viewWillAppear--[뷰가나타날것임]
Nextvc viewDidAppear--[뷰가나타남]
viewDidDisappear--[뷰가사라졌다]
  • Next View에서 버튼을클릭해서 첫화면으로 돌아가면 나타나는 함수
1
2
3
4
5
6
Nextvc viewWillDisappear--[뷰사라질것]
viewWillAppear--[뷰가나타날것임]
viewDidAppear--[뷰가나타났다]
Nextvc viewDidDisappear--[뷰사라짐]

------------- [ NextVc deinit: 메모리상의삭제됨 ] -----------

뷰생명주기

버튼을 사용해서 다음화면으로 넘어갈때의 뷰생명주기를 확인해보자 ( ios13버전)

card style

1
2
isModalInPresentation = true // 드래그로 끌어내려도 화면이 내려가지 않음
// FirstVC에서 넘겨줄때 사용해도되고, secondVC에서 직접 사용 할 수있음

Presenting(나를 띄운!!!) vs Presented(내가 띄운!!!)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
presentingViewController?.view.backgroundColor = .orange
// 나를 띄운놈에게 접근해서 그놈의 값, 동작을 바꿔줄 수 있음
presentedViewController?.view.backgroundColor = .black
// 내가 띄운놈에게 접근해서 값, 동작 변경도 가능

// nextView -> View
presentedViewController -> nil // 내가띄운것 - nextvc -> 없음
presentingViewController -> ViewController // 나를띄움놈 - viewvc -> nextvc

// FiestVc -> SecondVC -> ThirdVC
presentingViewController?.presentingViewController.view.backgrond
// 3번뷰에서 1번뷰의 변경시 단계를거쳐서 가는 방법이있음

// 3번에서 단계를 거치지않고 바로 닫고싶을경우
presentingViewController?.presentingViewController?.dismiss(animated: true)
  • 나를띄운놈에게 접근해서 그클래스의 프로퍼티에 접근하려했더니 되지않음.
  • presentingViewController -> UIView속성이고 나는 그 부모를 이용해서 view를 만들었기때문에 내가만든 클래스의 프로퍼티에 presentingViewController사용해서 접근할수는 없음.
  • 타입캐스팅을 통해 내가띄운놈이 ViewController이 맞는지 물어보고 맞다면 vc변수로 사용을하겠다. 그리고 그것에서 프로퍼티에 접근해서 변경해줄수 있다.
1
2
guard let vc = presentingViewController as? ViewController else { return }
vc.button.setTitle("클릭", for: .normal)

ios12버전의 뷰방식(Full Screen)

스크린샷 2019-12-07 오후 9.00.54

1
2
nextVC.modalPresentationStyle = .fullScreen //풀스크린모드 (#available(iOS 12.0, *))
nextVC.modalPresentationStyle = .automatic //오토메틱모드 (#available(iOS 13.0, *)) = 카드형

ios 13버전의 Card style

ios modalstyle

X-code

New Project

  • Organization Identifier: 일반적인 url의 반대로 입력
  • Bundle identifier: 파일명으로 인식
  • use core data: 데이터를 인터넷이아니고 자체앱에 쓸때
  • Include Unit tests: 내가 해놓은 코드를 테스트해서 이상이 없는지 확인하기 위한 테스트. 코드를 짜서 미리 앱이 돌아가기 전에 체크하는것
  • 체크하면 깃과 연동해줌 (옵션)
  • 왼쪽부터 두개의 아이콘은 swiftUI
  • command + shift + L: 단축키

X-code Image

  • 이미지나 컬러를 넣으면 리로스 사용이 가능함
  • 이미지의 위치조정이 가능
  • 이미지 위치 참고

UIGuide

# iPhone X Resolution
  • 디스플레이가 좋아질수록 1point안에 pixels이 4개가 될수도 9개가 될수도있다.
  • 우리가 봤을땐 물리적인 크기는 동일하더라도 실제 픽셀 화소가 달라지다보니 개발시 좌표랑 픽셀수가 달라진다.
  • 물리적인 크기는 크게 다르지 않더라도 픽셀의 차이는있다.
  • 개발에서는 포인트를 사용한다.

iPhone resolutions

  • iPhone 해상도를위한 최고의 가이드
  • 참고

Layered views

  • 하나의 화면을 볼때 몇개의 계층으로 나뉘어져있다.(View controller)
  • 내부에서는 레이어라는 존재로 뷰를 표현하며 UIwindow은 뷰를 표현하는 바탕

Coordinate system orientation

  • x, y 축의 시작지점
  • 맥OS는 좌측 하단이 기준점이다.

View Frame

  • View Frame 의 좌표는 상위뷰를 기준으로 결정
  • 내가 어느뷰에서 addSubview 했는지 상위뷰를 기준으로 x, y좌표가 정해진다.(주의!)

Frame and Bounds

  • frame
  • bounds: 본인을 기준으로 좌표가 0.0부터 시작되서 이동
  • super view는 0,0에서 시작하고 sub view는 super view위에 올려져있으므로 frame상의 x, y가 다르다.
  • frame으로 이동시에는 sub view도 함께 이동한다.
  • brounds로 이동시에는 본인의 위치에서 이동한다.

App Life Cycle

  • Model: 데이터를 저장하고 사용하는내용 (유저정보, 게임데이터, 지도정보, 각종데이터를 다루기위한 코드들)
  • View: 아이폰앱에서 우리가 표현하고싶은 View, 사용자가 직접보게되는 화면구성에 사용되는 Dbject, 한개 또는 여러개가 될수도 있다.
  • Controller: View와 Model사이의 중간 전달자역할. Model이 View에게 직접 전달하는것이아니고 Controller통해 전달을 한다.

Main run loop

  • 터치나, 줌인 줌아웃을 할때 먼저들어온게 먼저 처리하는것, 순환하면서 반복 이벤트가 발생하는것을 체크 한다. 여러가지 작업들을 처리함.

어플에 전달을하고 코어에 전달하고 os에전달하는 과정

State changes in iOS app

  • 라이프 사이클: 앱의생명주기, 뷰컨트롤러생명주기, 뷰의생명주기 등 (시작과 끝이 존재함)
  • Not running: 실행되지 않았거나, 시스템에 의해 종료된 상태
  • Foreground: 사용하는 앱의 상태
  • Inactive: 앱을 실행할때 잠깐 거치기도하지만, 전화등으로 앱이 잠깐멈출때도 해당 다른 앱으로 인해 앱이 멈춰져야하는 상태일때 Inactive로 전환된다.
  • Active: 현재 아이폰화면에서 어플리케이션이 실제로 활동하는 상태
  • Background: 동작은 혀용되는 상태(음악, 지도 등)
  • Suspended: 더이상 쓸 필요가 없거나 메모리가 부족해서 종료해야 하는 상태
  • 메모리에 남아는 있지만 동작(실행)은 하지않음. 담아는 두고 실행은 안시킴
  • Suspended상태에서 강제종료가 되면 다시실행할 때 처음부터 다시 런처화면을 띄운다.(Suspended -> Not running상태)
  • 이전 화면이 바로 올라오는 상태는 Suspended상태이고, Background상태일때에는 이전상태 그대로 올라온다.

Execution states for Apps

  • 어떤시점마다 처리할 것이 있다면 알려주고 그안에서 작업할수있는 메서드를 제공
  • 실행된직후 화면에 보이기 직전에 앱에서 호출되는 메서드(초기화작업)

Launch time

  • Launch time: 함수의 실행 이전에 시스템 실행 내용
  • Your code: 내가 신경써야하는 부분
  • 최종 초기화지점: didFinishLaunchingWithOptions
  • 프로젝트내에서는 메서드나 함수만 작성이 가능하다. 값은 할당할수있는데 프린트는 불가

->왜? 앱을실행시 메인함수가 먼저 실행되고 넘어가는데 메인을 생략하기 때문에 바로실행시키는 함수는 불가. 만약 사용시 탑레벨로 인한 오류가 발생하는데 탑이 main( )이여서 생략되어있기 때문에 불가함

  • @UIApplicationMain = main( ) 메인함수를 대신한다.(따로 main( )만들지 않아도됨 )
  • Main( ): 앱이 실행된다는 것 (앱의시작점), 가장먼저 호출, 메인함수로부터 모든게 시작 내가 만든 모든앱들이 여기를 통해 실행. 가장 기본이되는 정보를 넘겨줘서 시스템이 앱을 구동할수있는 역할.
1
2
3
4
5
6
7
8
9
10
11
12
13
1. SceneDelegate 사용할때

- ios 13 미만: 현업이나 개인앱낼때
- @available(iOS 13, *) : 붙여주면 13이상일때만 반응하고 아니면 무시함
- AppDelegate에 `var window: UIWindow?` 추가
- ios 13 이상 + SceneDelegate 사용기준: 공부할 때
- AppDelegate, SceneDelegate 무시

2. SceneDelegate 사용하지 않을때 (AppDelegate만 사용할 때)

- SceneDelegate 파일자체를 삭제,
- AppDelegate에서 `MARK: UISceneSession Lifecycle`(scene관련) 메서드삭제
- info.plist에서 application scene manifest키 삭제

Type Annotation & Type Inference & Literals

Type Annotation

  • 변수 선언 시 타입을 명확하게 지정하는 것
1
2
3
4
5
6
7
8
9
let year: Int = 2019

let language: String
language = "Swift"

var red, green, blue: Double
red = 255.0
green = 150.123
blue = 75

Type Inference

  • 변수 선언 시 값을 통해 변수의 타입을 추론하는 것
1
2
3
4
5
6
7
8
9
10
11
let name: String = "Babo"
type(of: name) // String.type

let age: Int = 7
type(of: age) // Int.type

var weight = 48.3
type(of: weight) // Double.type

var isDog = true
type(of: isDog) // Bool.type

Literals & Types

  • 리터럴: 고정된 값으로 표현되는 문자 그 자체
  • 정수 / 실수 / 문자 / 문자열 / 불리언 리터럴 등

Operator

Ternary Operator 삼항연산자

  • 결과: ? 앞의 식이 참일때 True : False
1
2
3
4
5
6
7
a > 0 ? "positive" : "zero or negative"

if a > 0 { // 삼항연산자와 동일하게 동작
"positive"
} else {
"negative"
}

Assignment Operators 할당연산자

1
2
3
4
5
6
7
8
9
10
11
12
value += 1
//value = value + 1 위와같은
value -= 5
//value = value - 5
value *= 2
//value = value * 2
value /= 2
//value = value / 2
value %= 2
//value = value % 2 //나머지가 나옴

// 미지원 : value++, value--

Arithmetic Operators 산술 연산자

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 실수에서의 나눗셈
let e = 123.4
let f = 5.678

e / f // 단순히나누면 나머지가 틀림: 21.73300457907714

// 실수로 나머지를 구할때 사용
// 나머지 구하기 (내림)
e.truncatingRemainder(dividingBy: f) // 4.162000000000007

// 나머지 구하기 계산 방법
let quotient = (e / f).rounded(.towardZero) // 몫: 21
let remainder = e.truncatingRemainder(dividingBy: f) //나머지: 4.162000000000007
let sum = f * quotient + remainder // 123.4
5.678 * 21 // 119.238
5.678 * 21 + 4.162000000000007 // 123.4

Question

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
// 범위 연산의 순서를 반대로(내림차순) 적용하려면?

// 반대 reversed
for index in (1...5).reversed() {
print("\(index) times 5 is \(index * 5)")
}

//결화
5 times 5 is 25
4 times 5 is 20
3 times 5 is 15
2 times 5 is 10
1 times 5 is 5

// 10~1까지 -1로
for index in stride(from: 10, through: 1, by: -2) {
print("\(index) times 5 is \(index * 5)")
}

//결과
10 times 5 is 50
8 times 5 is 40
6 times 5 is 30
4 times 5 is 20
2 times 5 is 10

Function

  • Input 과 Output 이 모두 있는 것 (Function)

  • Input 이 없고 Output 만 있는 것 (Generator)

  • Input 이 있고 Output 은 없는 것 (Consumer)

  • Input 과 Output 이 모두 없는 것

1
2
3
4
// 기본유형
func <함수이름> (<parameterName>: <Type>) -> <ReturnType> {
<statements>
}

Input이 없는 경우

1
2
3
4
5
6
7
8
func hello1() {
print("Hello, world!")
}

//
func hello2() -> String {
return "Hello, world!"
}

Output이 없는 경우

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
func say(number: Int) {
print(number)
}
// void는 반환값이 없음 ()대체하거나 생략가능
func say(word: String) -> Void {
print(word)
}

func say(something: String) -> () {
print(something)
}

// 3개는 같음
say(number: 1)
say(word: "1")
say(something: "1")

Input 과 Output 이 모두 있는 것

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
func greet(person: String) -> String {
let greeting = "Hello, " + person + "!" // greet함수 내에서만 사용되는 상수(greeting)
return greeting
}

greet(person: "Anna") // 함수사용

func addNumbers(a: Int, b: Int) -> Int {
return a + b
//한줄만 사용시 return생략 가능 , print를 붙이면 return도 붙여줘야함
}

let x = addNumbers(a: 10, b: 20) // x = 30
let y = addNumbers(a: 3, b: 5) // y = 8
x + y // 38

Input 과 Output 이 모두 없는 것

1
2
3
4
5
6
7
8
let outside = "outside"
func scope() { // 반환값이 없으므로 return 사용 안함
print(outside)
let inside = "inside"
print(inside)
}

scope() // outside; inside;

Argument Label

  • argumentName: 외부에서 호출
  • parameterName: 함수내에서사용
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
func functionName(argumentName <parameterName>: <Type>) {
}

func someFunction(_ firstParam: Int, secondParam: Int) {
print(firstParam, secondParam)
}

// someFunction(firstParameterName: 1, secondParameterName: 2)
someFunction(1, secondParam: 2)
// _를 넣으면 값만 넣을수있음

func summary(num1 a: Int, num2 b: Int) -> Int {
a + b
}
// 함수 내에서는 a, b로쓰이고 함수 밖에서는 따로 불러서 사용시엔 num1, num2로사용됌

summary(num1: 1, num2: 2)

Variadic Parameters 가변 파라미터

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
func average(_ numbers: Double...) -> Double {
var total = 0.0
for a in numbers {
total += a
}
return total / Double(numbers.count)
}

average(1, 2, 3, 4, 5) // 3
average(3, 8.25, 18.75) // 10

func average1(_ numbers: Double..., and last: Double) {
//네임의 끝을 지정해주거나 첫번째를 지정해줘야함
print(numbers)
print(last)
}

average1(1, 2, 3, and: 5) // [1.0, 2.0, 3.0]; 5.0;
average1(1,2,3,4,5,6, and: 8873646) // [1.0, 2.0, 3.0, 4.0, 5.0, 6.0]; 8873646.0;

Nested Functions 중첩함수

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
/* 
함수 function1을 만들고, 그안에 또다른 함수를 중첩 해넣는다.
if 문을 사용하여 function1의 함수의 파라미터 네임을 사용해 만들어서 true, false일때
다른값이 나오도록 한다.
*/
func function1(backward: Bool, value: Int) -> Int {
func stepForward(input: Int) -> Int {
return input + 1
}
func stepBackward(input: Int) -> Int {
return input - 1
}

if backward {
return stepBackward(input: value)
} else {
return stepForward(input: value)
}
}

var value = 4
chooseStepFunction(backward: true, value: value) // 3
chooseStepFunction(backward: false, value: value) // 5

chooseStepFunction(backward: true, value: 3) // 2
chooseStepFunction(backward: false, value: 3) // 4

터미널 기본 명령어 숙지

http://www.ciokorea.com/news/29239

리눅스 초보자가 익혀야 할 12가지 명령어

  1. man : 다른 명령어에 대해 알고자 할때 사용 man man 입력시 man명령어 자체를 소개하는 페이지를 볼 수 있다. man xxx 방식으로 사용

  2. ls: 현재 디렉토리 내용. ls ~입력시 루트 디렉토리 파일을 보여줌

  3. pwd: 현재 작업중인 디렉토리 확인 명령. 나의 위치

  4. cd: 이동명령. cd Desktop

  5. mkdir: 디렉토리(폴더) 생성. mkdir pictures_(폴더삭제 명령어는 rmdir)

  6. find, locate: 특정파일을 찾을때 두가지모두 사용가능

  7. cp: 파일의 사본을 새로운 이름으로 생성하고자 할때. cp cats dogs 입력시 cats파일의 사본을 dogs란 이름으로 생성한다. cats파일은 그대로 있다.

  8. mv: 파일을 이동하거나 다른파일로 옮길때, 또는 두가지 작업을 모두 수행할 때 사용하는 명령. mv cats dogs입력시 cats파일의 이름을 dogs로 바꿔준다. mv cats ~/Desktop라고 입력하면, cats 파일을 Desktop폴더로 옮겨준다.

  9. more: 파일의 내용을 한 번에 한 화면씩 보여준다.

  10. kill: Application실행을 중지하고 싶을때. 보통 kill은 ps다음에 사용한다. ps 명령어로 죽이고싶은 Application의 정확한 프로세스 ID를 확인한다.

  11. sudo: 일반사용자가 Application을 설치해야 한다면 sudo명령어로 루트 권한을 임시로 부여할 수 있다. 하지만 패스워드를 입력해야한다.

  12. passwd: 패스워드 변경해야할때 입력하면, 현재 패스워드와 new패스워드를 입력하라고 한다.

Vim tutor

Vim 명령어참고

  • 최소한 Lesson 2 요약까지 따라하기
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
LESSON1.
h: 왼쪽 j:아래 k:위 l:오른쪽
w:다음단어 시작으로 점프 b:이전단어 시작으로 점프
0: 행의 처음으로 점프 $: 행의 끝으로 점프
gg: 문서 첫 행으로 점프 G: 문서 마지막 행으로 점프
숫자G: 숫자행으로 점프
<esc> :q! <enter> 수정내용을 무시한 채로 빠져나가려면
<esc> :wq <enter> 저장 후 빠져나가려면

LESSON2.
-삽입: i를 누르고 텍스트를 입력하고 <esc>를 누른다.
참고) <esc>는 명령모드로 돌아가는데 쓰며, 원치 않는 명령이나 완전히 입력되지 않은 명령을 취소할때도 쓴다.
-삭제: 명령모드에서 커서가 위치한 곳의 글자를 지우려면 x입력.
dw: 한 단어를 끝까지 지울때
d$: 그 줄끝까지 지울때
dd: 한줄 지울때 '4dd'=4줄지움
-삭제명령 d의형식은 [횟수] d 대상(w,e,$) / 횟수는 입력안하면 기본값=1
-취소: u를 누르면 마지막 명령이 취소 / U는 줄전체를 수정

LESSON 3.
-p: 이미 지운 내용을 되돌릴때
-r: delete와 같음. 수정할 글자에서 r누르고 바꾸어 넣을 글자를 입력
-cw: 커서 위치에서 단어의 끝까지 바꿀 때
-c$: 줄 끝까지 바꿀 때

LESSON 4.
1.위치
-SHIFT+G를 누르면 파일 내의 줄로 이동
-ctrl+g: 파일 이름과 현재 위치한 줄 표시
-SHIFT+G: 파일의 맨 마지막으로 이동
-돌아가야할 줄을 입력후 shift+g를 누르면 그줄로 이동

2.찾기
-/를 누르고 검색할 문구 입력(아래 방향으로 찾음)
-?를 누르고 검색할 문구 입력(위 방향으로 찾음)
-n: 같은 문구를 다시 찾을 때
-SHIFT+N: 같은 문구를 반대방향으로 찾을 때

3.%: 괄호 짝 찾기 (,[,{ 커서를 놓고 %누르면 짝 찾아줌
-짝이 맞지 않는 괄호가 있는 프로그램을 디버깅할 때 매우 유용

4.에러수정
어떤 줄에 처음 등장하는 old를 new로 바꾸려면 :s/old/new
한 줄에 등장하는 모든 old를 new로 바꾸려면 :s/old/new/g
두 줄 #,# 사이에서 치환을 하려면 :#,#s/old/new/g
파일 내의 모든 문구를 치환하려면 :%s/old/new/g
바꿀 때마다 확인을 거치려면 'c'를 붙여서 :%s/old/new/gc

LESSON 5.
- :!를 이용해 외부 명령 실행
:!ls - 디렉토리의 목록을 보여준다.
:!rm FILENAME - FILENAME이라는 파일을 지운다.
:W name -현재 사용하는 파일을 name라는 이름으로 저장.
:#,#w name -#부터 #까지의 내용을 name라는 이름으로 저장.
:r name -디스크에서 name라는 파일을 불러들여 커서 위치 뒤에 넣는다.

LESSON 6.
o: 아래에 줄만들고 편집모드
O: 위에 줄만들고 편집모드
a: 다음에 글을 입력(i누르고 글자넣고 하는 번거로움 생략)
A: 그 줄의 끝에 글을 추가
R: 하나 이상의 글자를 변경(r은 한개만 변경 하고 자동종료)
-옵션(set)설정-
:set ic (대소문자 구별 없이 찾음)
:set hls is (찾은 내용을 강조시킴)
:nohlsearch (강조없애기)

진법, 연산개념, 네이밍컨벤션


2진법, 8진법, 10진법, 16진법 간 변환 개념 숙지

  • 2진법: 0과 1로 나타내는 숫자표기
  • 2진법은 2로나누고, 8진법은 8로나누고 16진법은 16으로 나누는것
1
2
3
4
5
6
7
8
9
10
11
12
2진법 자리수        
16 8 4 2 1
0 0 0 0 0

*10110(2)
26(8), 16+4+2 = 22(10), 16(16)
-2진법에서 다른진법으로 변환할땐 2가지방법이 있음
1. 10진법 변환은 16+4+2=22
2. 16진법 변환시엔 4자리씩 끊거나/10진법에서 나누기
(0001)(0110)=(1)(6)=16
3. 8진법 변환시엔 3자리씩 끊기/10진법에서 나누기
(010)(110)=(2)(6)=26

비트 연산자, 논리 연산자 개념 숙지

  • 논리연산자: 참(True) 또는 거짓(False), 두자기 논리 값을 다루기 위한 연산자
  • AND(&&) / OR(||) / NOT(!)
1
2
3
4
5
6
7
A B   AND(&&) OR(||)
0 0 0 0
0 1 0 1
1 0 0 1
1 1 1 1

* AND는 곱하기, OR은 더하기로 생각하며 이해하기 쉽니다.
  • 비트연산자: 값을 반환한다.
Operator Description
& AND연산. 둘다 참일때만 참
l OR연산. 둘중 하나만 참이여도 참
^ XOR연산. 둘중 하나만 참일때 참
~ 보수 연산.
<< 왼쪽 시프트 연산자. 변수의 값을 왼쪽으로 지정된 비트 수 만큼 이동(*2)
>> 오른쪽 시프트 연산자. 변수의 값을 오른쪽으로 지정된 비트 수 만큼 이동(/2)
1
2
3
4
5
6
7
8
9
10
예시) a = 60 (0011 1100) / b = 13 (0000 1101)

0011 1100 0011 1100 0011 1100
& 0000 1101 | 0000 1101 ^ 0000 1101
----------- ----------- -----------
0000 1100 0011 1101 0011 0001

~ 0011 1100 0011 1100 << 1 0011 1100 >> 1
----------- -------------- --------------
1100 0011 0111 1000 (120) 0001 1110 (30)

Swift 네이밍 컨벤션 이해하기

  • 코드는 쓰는 시간만큼이나 읽는 시간도 엄청 많이 소요된다.
  • 프로그래머 업무의 절반 이상은 이름 짓기

위키위키위키위키위키백과!

PascalC**ase = 파스칼 표기법

  • 첫 단어를 대문자로 시작하는 표기법
    • 예) int MyFirstVariable;
  • Swift 에서는 filename, class, struct, enum, protocol 및 type 에 대해 이것을 사용

camelCase = 카멜 표기법

  • 각 단어의 첫문자를 대문자로 표기하고 붙여쓰되, 맨처음 문자는 소문자로 표기
  • 띄어쓰기 대신 대문자로 단어를 구분하는 표기방식
  • 변수명을 모두 소문자로 쓴다. 여러 단어가 이어지는 경우 첫단어를 제외하고 각 단어의 첫글자만 대문자로 지정해 주는 방식.
    • 예) int myFirstVariable;
  • 선언한 변수는 세단어로 되어있다. my, first, variabl
  • 모두 소문자로 작성하되, 첫단어를 제외한 각 단어의 첫글자를 대문자로 쓴다.
  • Swift 에서는 변수명, 함수, 메서드 등 pascal case 이외에 모두 camel case 사용

실수를 표현하기 위한 고정 소수점, 부동 소수점 방식 (IEEE 754)이 어떻게 다른지

  • 고정소수점: 말 그대로 소수점이 고정된 형태
    • 실수를 정수부와 소수부로 분할표현해서 비교적 단순
    • 표현의 범위가 넓지 않음
    • 간단한 성적처리조차 힘듬
  • 나. 부동소수점: 소수점 이동이 가능
    • 실수를 가수부+지수부로 나누어 표현
    • 가수: 실수의 실제값
    • 지수: 크기를 표현, 가수의 어디쯤에 소수점이 있는지를 나타냄
    • 즉 지수의 값에 따라 소수점이 움직이기때문에 이방식으로 표현하는 방법을 부동소수점 이라고 한다.
    • 고정소수점과는 다르게 표현할 수 있는 범위가 넓어짐
    • 가수부가 지수부보다 길어서 정밀도가 비교적 충분(무한하진 않음)

IEEE 754 위키백과

  • 부동소수점 표현 유튜브

  • 컴퓨터에서 부동소수점을 표현하는 가장 널리 쓰이는 표준.

컴퓨터 동작 개념 이해를 위한 동영상 시청