[Swift] Swift 기초 공부 - 1 : 둘러보기

Sean·2023년 5월 23일
0

Swift 기초 공부

목록 보기
1/2

누군가에게 알려주기 보다는 나 스스로 정리 하며 언젠가 다시 사용할 때를 대비하는 글을 작성할것이다.

참고자료 : swift.org

시작

시작글

  • 현재 나는 Objective-C 와 Swift 언어로 iOS앱의 개발을 할 수 있지만 뭔가가 부족한 느낌을 항상 받았다.
    거진 다 아는 내용이지만 머리로는 알겠는데 말로 하거나 조금만 심화로 Deep 하게 들어가면 부족한 것을 너무 절실하게 느꼈다.
    그래서 기초가 조금 더 탄탄했으면 했는데 그 기초를 다시 공부하면서 조금 더 탄탄하게 쌓을 생각이다.

  • 당연하게도 이 글은 기초 공부지만 어느정도 swift를 아는 놈이 작성하는거라 문서를 보고 하지만 약간 야매같은 느낌으로 이 글을 딱딱하게 책을 읽듯 요약하는게 아니라 나만의 방식으로 유연한 요약을 목표로 할 생각이다.

분석

Welcome to Swift

What is Swift?

swift는 문서에 따르면 새로 배우기 쉽고 표현하기 좋으며 재밌는 언어다.
또한 최신 프로그래밍 패턴을 채택해 많은 클래스의 일반적 오류를 정의한다.

  • 변수는 항상 사용 전 항상 초기화 되어야 한다.
  • Array의 인덱스는 범위 초과 에러에 대해 검사해야 한다.
  • 정수는 오버플로우 검사되어야 한다.
  • 옵셔널은 nil값이 명시적 처리되도록 한다.
  • 메모리는 자동으로 관리된다.
  • 에러 처리 통해 예기치 않은 오류 처리 가능하다.

강력한 타입 추론과 패턴 매칭을 통해 간결한 표현이 가능하다.

결국에는 Swift에 대한 자랑이라서 중요하다 싶은 부분만 요약하고 넘어가겠다.

A Swift Tour

swift는 입력/출력 또는 문자열 처리와 같은 기능을 위한 별도의 라이브러리가 필요 없다.
전역 범위로 작성한 코드는 전체에서 사용되기에 main()이 필요 없다.
모든 구문의 끝에는 세미콜론도 필요 없다.
해당 부분에서는 swift에 대한 간단한 코드 작성 방법에 대해서 알려준다.

swift는 main() 필요없고 세미콜론(;)도 굳이 붙일 필요 없음


간단한 값

상수 선언 = let / 변수 선언 = var

항상 타입을 명시해야 하는것은 아니다. 값을 제공하면 컴파일러는 타입을 유추한다. 하지만 초기값이 충분한 정보를 제공하지 않거나 없는 경우 뒤 콜론(:)으로 구분해 타입을 지정한다.

let intNumber: Int = 30

만들어진 값은 다른 타입의 값으로 절대 변경되지 않는다.
값을 다른 타입으로 변경해야 하면 원하는 타입의 인스턴스를 만들어야 한다.

Int에서 String로 변환하는 경우에는 다음과 같이 할 수 있다.

let intNumber: Int = 10
let strText: String = "Test Text"
let numberText: String = strText + String(intNumber)

이렇게 작성을 하는 방법도 있지만 조금 더 쉬운 방법도 존재

let intNumber: Int = 10
let numberText: String = "Test Text \(intNumber)"

이렇게 작성을 하게 되면 두 코드는 똑같은 값을 내보내게 될 것이다.
또한 \() 안에 인스턴스가 들어가기에 단순 변수나 상수 뿐 아니라 내부에서 특정한 동작을 할 수 있다.

String 에서 여러 문자열을 입력하고 싶으면 """ 를 사용해서 작성한다.

대괄호 [ ]를 사용하여 배열(Array) 딕셔너리(Dictionary)를 생성할 수 있다.

let arrayTest: [String] = ["A","B","C"]
let dictTest: Dictionary<String, String> = ["A":"a","B":"b"]

요소를 추가함에 따라 자동으로 그 크기는 증가한다.
변수와 마찬가지로 빈 값으로 선언도 가능하다.

var arrayEmpty: [String] = []
var dictEmpty: [Sting: String] = [:]

빈 값으로 배열과 딕셔너리를 할당하려면 그 타입을 명시해줘야 한다.
Dictionary의 타입 명시 방법은 위와 아래 방법 편한거로 사용하면 된다.

타입 추론이 참으로 좋은 방법이긴 하고 편하긴 하지만 개인적으로 나는 모든 타입의 선언시에 전부 타입을 명시하는 편이긴하다.
|
속도 면에서도 그렇지만 유지보수를 위해 단순히 변수만 보고 이 변수가 어떠한 타입인지 바로바로 알 수 있다는 큰 장점이 있기 때문이다.
|
여러 타입에 대해서는 후에 더 자세하게 설명이 될 예정이다.


제어 흐름

조건문

  • 조건문을 둘러싼 소괄호는 선택 사항이나 중괄호는 필수 사항이다.
if (조건) { 
	... 
} else if (조건2) {
	... 
} else {
	...
}

switch (조건) {
case (요소1):
	...
case (요소2):
	...
default:
	...

반복문

  • 반복문을 둘러싼 소괄호는 선택사항이나 중괄호는 필수 사항이다.
  • 가장 근처의 반복문을 탈출하기 위해서는 break를 사용한다.
for i in 0 ..< 5 {
	...
}

while i < 10 {
	...
}

repeat {
	...
} while i < 10

조건문과 반복문에 대해서는 조금 더 심화 과정이 있으나 해당 부분에서는 단순히 이런게 있다는 느낌으로 진행이 되기에 조금 심화 부분은 후에 해당 부분에서 작성할 예정이다.


함수와 클로저

함수

  • 함수를 선언하기 위해서는 func을 사용한다.
  • 소괄호 안에 인수의 리스트를 입력하고 반환 타입은 파라미터와 구분을 위해서 -> 이후에 작성한다
func testMakeFunc(first: Int) -> Int {
    return 1
}

매개변수 vs 인수
인수는 해당 함수를 호출하여 데이터를 전달하는 값을 인수(argument)라고 하는거고 함수를 만들때 함수의 선언부에 들어가는 즉 전달된 값을 받는 변수를 매개변수(parameter)라고 한다.
|
요거는 용어적인 구분인데 이정도는 제대로 구분을 하고 있는게 좋을 듯 하여 이렇게 따로 작성을 하였다.

함수는 1급 타입 = first-class type 으로 이것은 함수가 다른 함수를 값으로 반환할 수 있다는 뜻이다.
또한 다른 함수를 인수로 받을 수 있다.

func testFunc(first: (Int) -> Bool) -> ((Int) -> Bool) {
	func addTest(number: Int) -> Bool {
		if number == 1 {
			return true
        }
	}
    
	if first {
        return addTest(number: 1)
    } else {
    	return addTest(number: 2)
    }
}

func checkResult(number: Int) -> Bool {
	if number == 1 {
    	return true
	}
    return false
}

testFunc(first: checkResult)

함수는 거의 이게 전부라고 보면 될 정도로 그 사용이 복잡하지는 않다. 하지만 조금 심화되는 부분이 있기에 해당 부분에 대해서는 함수 파트에서 따로 작성할 예정이다.

클로저

클로저에 대해서는 함수의 일종이라 보면 된다.
해당 부분은 이곳에서 짧게 다룰바에 그냥 클로저만 따로 다루는게 맞다 생각해 이 부분은 넘기도록 하겠다.


객체와 클래스 (Object and Class)

클래스

  • 클래스 내에서 프로퍼티의 선언은 클래스 내에 있다는 점을 제외하고는 모두 동일하다.
  • 클래스 이름 뒤에 소괄호 ( )를 넣어 클래스의 인스턴스를 생성할 수 있으며 인스턴스의 프로퍼티와 메서드에 접근하기 위해서는 점 . 구문을 사용한다.

클래스를 생성할 때 내부의 프로퍼티라던가 init, getter, setter, self, 등 여러 부분에 대해서는 후에 클래스와 관련된 부분에서 조금 더 자세하게 작성할 예정이다.


열거형과 구조체 (Enumerations and Structres)

열거형

  • 열거형 생성을 위해서 enum을 사용한다. 열거형도 메서드를 가질 수 있다.

구조체

  • 구조체 생성을 위해서 struct을 사용한다.
  • 구조체는 메서드와 초기화 구문을 포함해 클래스와 동일 한 동작을 많이 지원한다.

열거형과 구조체의 좀 더 자세한 활용 방법은 뒤에서 다룰 예정이다

구조체와 클래스
이 두 타입은 매우 비슷한 동작을 지원한다.
하지만 둘의 가장 큰 차이점은 구조체는 항상 복사되어 값으로 전달이 되지만 클래스의 경우에는 참조로 전달이 된다는 차이가 있다.
|
해당 내용에 대해서는 구조체 부분에서 조금더 자세히 다룰 예정이다.


동시성

비동기적 실행 함수를 나타내기 위해서 async를 사용한다.

func asyncFunc() async -> Int {
	return 1
}

앞에 await를 작성하여 비동기 함수를 호출하는 것을 나타낸다.

let asyncLet = await asyncFunc()

비동기 함수 호출 위해 asnyc let 을 사용해 다른 비동기 코드와 병렬 실행이 가능하다. await 를 사용해 반환값을 사용한다.

비동기 함수의 반환을 기다리지 않고 동기 코드에서 비동기 함수 호출 하려면 Task를 사용한다.

func asyncLetFunc() async {
	async let number = asyncFunc()
}

Task {
	await asyncLetFunc()
}

이 부분은 이렇게 글로 요약 된걸 봐봤자 잘 모른다.
그냥 동기와 비동기가 무슨 차이인지 둘을 왜 구분을 해서 사용을 해야 하는건지 그런거만 잘 생각해보고 자세한 내용은 후에 확인을 하도록 하자


프로토콜과 확장 (Protocol and Extensions)

프로토콜

  • 프로토콜 선언을 위해서는 protocol을 사용한다.
  • 클래스, 열거형, 그리고 구조체는 프로토콜을 채택할 수 있다.

확장

  • 새로운 메서드와 계산된 프로퍼티와 같이 존재하는 타입에 기능을 추가하려면 확장 (extension)을 사용한다.
  • 확장을 사용하여 다른 곳에서 선언된 타입이나 라이브러리 등 여러 타입에 프로토콜 준수를 추가 할 수 있다.

프로토콜과 확장
이 두 가지는 매우 중요하고 자주 쓰이는 부분이다.
자세한 활용 방법은 뒤에서 다시 작성하겠다.


에러 처리

에러를 던지기 위해서 throw를 사용하고 에러를 던질 수 있는 함수를 나타내기 위해서 throws를 사용한다.
함수에서 에러가 발생하면 함수는 즉시 반환된고 호출한 코드가 에러를 처리한다.

func errorThrowFunc() throw {
	...
}

에러를 처리하는 방법은 몇가지가 존재 하는데 하나의 방법으로는 do-catch 를 사용하는 것이다.
do 블럭 내에서 앞에 try를 작성해 에러가 발생할 수 있는 코드임을 표시한다.

func errorDoCatchFunc() {
	do {
		let check = try errorThrowFunc()
	} catch {
    	print("ERROR: \(error)")
    }
}

catch 블럭 내에서 에러는 다른 이름으로 지정하기 전까지는 error 이라는 이름으로 주어진다.

특정 에러를 처리하는 여러개의 catch 블럭을 제공할 수 있으며 switch 에서 하는 것처럼 사용하면 된다.

해당 부분을 자세하게 다루는 방법은 후에 조금 더 자세하게 설명하도록 하겠다.


제너릭

제너릭은 꺾쇠 < >안에 이름을 작성해서 생성한다.
제너릭은 함수와 메서드 뿐 아니라 클래스와 열거형, 구조체도 만들 수 있다.

func makeGenericFunc<T>(num: T) -> T {
    return num
}

enum GenericEnum<T> {
	case none
    case some(T)
}

요구사항의 리스트들을 지정하기 위해서는 본문 바로 전에 where을 사용해야 한다. 타입이 프로토콜을 구현하도록 요구하거나 클래스에 특정 상위 클래스가 있어야 한다든가 하는 요구를 필요로 할 때 말이다.

제너릭도 잘 활용하면 아주 유용한 도구가 되므로 지금은 이런게 있다는것만 알아두면 된다.

참고자료

기타

당연 틀린 부분 지적은 감사하나 비난은 정중하게 사양하겠다.

  • 엄청나게 주관적으로 요약을 해서 작성을 하긴 했는데 지금 이 포스트에서는 그냥 이런게 있구나 하는 정도로만 넘어가면 될듯 하여 이렇게 작성하였다.
profile
"잘 할 수 있을까?"를 고민하기보단 재밌어 보이는건 일단 하고, 잘하기 위해 그냥 계속합니다.

0개의 댓글