Swift문법 간단 정리-2
함수개요
1급객체
클로저표현식
함수
기본형태
func div(_ x:Double, by y: Double = 1) -> Double {
let result = x / y
return result
}
print(type(of:div)) //함수의 타입:(Double,Double)->Double
|
cs |
함수를 호출할 때 사용하는 것을 argument,인자
함수 내부에서 사용하는 것을 parameter 라고 표현
리턴값 여러개를 반환 (튜플형태)
import Foundation
func calc (x:Int, y:Int) -> (Int, sub:Int, div:Double){
let sum = x + y
let sub = x - y
let div = Double(x) / Double(y)
return (sum, sub, div)
}
let result = calc (x:10, y:3)
print(result.0) //4
print(result.1) //7
print(String(format:"%.2f",result.div)) // 3.33
print(type(of:calc)) //(Int,Int) ->(Int, sub:Int, div:Double) |
cs |
튜플형태로 반환하기 때문에 인덱스 또는 레이블로 접근이 가능
가변 매개변수
func add (numbers:Int...)->(Int){
var sum = 0
for i in numbers{
sum += i
}
return sum
}
print(add(numbers:1,2,3,4,5)) //15
print(type(of:add)) // (Int...) -> Int
|
cs |
Call by reference
func plus (x: inout Int) -> Int {
x += 5
return 0
}
var value = 10
plus(x:&value)
print(a) // 15
|
cs |
1급객체
Swift의 함수는 1급객체 속성을 가집니다
함수를 변수에 담아 매개변수 혹은 리턴으로 사용할 수 있습니다.
func double(num: Double) -> Double{
print(#function) // 함수명출력
return num * 2
}
func half(num: Double) -> Double{
print(#function)
return num / 2
}
let toDouble = double //double함수를 toDouble변수에 저장
print(double(num:12.0)) //함수명:double(num:) 24.0
print(toDouble(12.0)) //함수명:double(num:) 24.0 레이블생략해야함
let toHalf = half
func upDown(Func:(Double) -> Double, value: Double){
let result = Func(value) //레이블생략
print("결과 = \(result)")
}
upDown(Func: toDouble, value:8.0) //'double(num:) 결과 = 16.0' == toDouble(8.0)
upDown(Func: toHalf, value:8.0) //'half(num:) 결과 = 4.0' == toHalf(8.0)
func decideFun(x: Bool) -> (Double)->Double{
if x{
return toDouble
} else{
return toHalf
}
}
let r = decideFun(x: false)
print(type(of:r)) // (Double) -> Double
print(r(10.0)) //half(num:) 5.0 == toHalf(10.0)
|
cs |
함수 호출시 입력될 값을 argument 인수
함수 내부에서 사용될 값은 parameter 매개변수, 이자
클로저 표현식
(캡처?개념)
공식문서에 따르면 함수는 namedClosure라고도 표현합니다.
우리가 클로저라고 부르는 것은 unnamed closure인데 짧게 클로저 라고 부르는 것입니다.
표현식은 헤더와 바디 구분되고 in키워드를 통해 구분합니다
클로저의 기본 표현식은 아래와 같습니다
{(x:Int, y:Int) -> Int in
return x + y
}
|
cs |
함수와 마찬가지로 1급객체의 속성을 갖습니다
let add = {(x:Int, y:Int) -> Int in
return x + y
}
print(add(3,5)) //8
|
cs |
후행 클로저
클로저도 1급객체이기 때문에 인자 혹은 리턴에 사용할 수 있습니다.
마지막 매개변수로 클로저를 사용할 경우 매개변수이름을 생략하여 외부 블럭에 작성할 수 있습니다
func concatenate(x:String, y:String, concat: (String,String) -> String) ->String{
return concat(x,y)
}
var result1 = concatenate(x:"토끼", y:"거북이", concat:{(val1:String, val2:String) -> String in
return "\(val1)는 \(val2) 보다 빠르다"
})//클로저
var result2 = concatenate(x:"토끼", y:"거북이") {(val1:String, val2:String) -> String in return "\(val1)는 \(val2) 보다 빠르다"
}//후행클로저
print(result)//토끼는 거북이보다 빠르다
|
cs |
단축형식
-리턴형 생략
컴파일러의 타입추론을 통해 리턴형을 생략할 수 있습니다
var result1 = concatenate(x:"토끼", y:"거북이", concat:{(val1:String, val2:String) in
return "\(val1)는 \(val2) 보다 빠르다"
})//클로저
var result2 = concatenate(x:"토끼", y:"거북이") {(val1:String, val2:String) in
return "\(val1)는 \(val2) 보다 빠르다"
}//후행클로저
|
cs |
-매개변수 생략, 단축인자 사용
입력된 매개변수 순서를 통해 식별합니다
var result1 = concatenate(x:"토끼", y:"거북이", concat:{
return "\($0)는 \($1) 보다 빠르다"
})//클로저
var result2 = concatenate(x:"토끼", y:"거북이") {
return "\($0)는 \($1) 보다 빠르다"
}//후행클로저
|
cs |
-eturn 키워드 생략
마지막줄은 return으로 간주합니다
var result1 = concatenate(x:"토끼", y:"거북이", concat:{
"\($0)는 \($1) 보다 빠르다"
})//클로저
var result2 = concatenate(x:"토끼", y:"거북이") {
"\($0)는 \($1) 보다 빠르다"
}//후행클로저
|
cs |
클래스
클래스는 인스턴스를 생성했을 때 어떤 모습으로 보이게 할것인지 정의 한 것
메서드
인스턴스메서드 : 객체가 호출할 메서드
클래스(타입)메서드: 클래스가 호출할 메서드 (static 메서드)
class Man{
var age: Int = 16
var weight: Double = 60.2
var job:String = "jobless"
func display(){
print("나이:\(age), 몸무게:\(weight), 직업:\(job)")
}
class func classM(){
print("classM 클래스메서드 입니다.")
}
static func staticClassM(){
print("staticClassM 클래스메서드 입니다(static)")
}
}
Man.classM()//classM 클래스메서드 입니다.
Man.staticClassM()//staticClassM 클래스메서드 입니다
var Cho: Man = Man()
Cho.display()//나이:16, 몸무게:60.2, 직업:jobless
//Cho.classM() //에러
|
cs |
프로퍼티
클래스 내부에 사용할 변수,상수
stored프로퍼티 : 일반적인 프로퍼티 - 초기값이 필수 ( 초기화 / 생성자init() / 옵셔널타입)
computed프로퍼티 : 계산으로 값이 정해지는 프로퍼티, 프로퍼티가 설정, 호출되는 시점에 값이 결정됨
class Man{
var age = 19
var kg_w: Double //초기화를 생략해도 정상동작
var lb_w: Double{
get{ //setter가 없으면 생략가능
return kg_w * 2.2
}
set(lb_w){//인자는 변수와 같은 타입, newValue는 생략가능
kg_w = lb_w / 2.2
}
}
func display(){
print("나이:\(age),몸무게(kg):\(kg_w),몸무게(lb):\(lb_w)")
}
init(age:Int, weight:Double){
self.age = age
kg_w = weight
}
}
var Choi: Man = Man(age:2, weight:17.5)
Choi.display()
//나이:2, 몸무게(kg):20.5, 몸무게(파운드):45.1
print(Choi.age)//2
print(Choi.kg_w)//17.5
print(Choi.lb_w)//38.5 getter호출
Choi.lb_w = 38.5 //setter호출
print(Choi.kg_w)//18.5
print(Choi.lb_w)//40.7 getter 호출
|
cs |
getter는 값이 프로퍼티가 호출되는 호출되는 시점 setter가 없다면 생략가능
setter는 프로퍼티값이 수정되는 시점
생성자 init()
클래스, 열거형, 구조체 등 인스턴스를 생성하는 시점에서 꼭 실행해야 할 초기화 작업을 정의한 것
Default initializer
별도의 생성자를 정의하지 않을 때 호출됩니다
생성자를 하나라도 정의하면 사라집니다
Designated initializer
모든 프로퍼티를 초기화시키는 생성자
class Man{
var age: Int = 16
var weight: Double //생성자 덕분에 초기화 생략가능
var job:String = "jobless"
func display(){
print("나이:\(age), 몸무게:\(weight), 직업:\(job)")
}
init(yourage:Int, yourweight:Double, _ yourjob:String){
self.age = yourage
weight = yourweight
job = yourjob
}
}
//var Cho: Man = Man()// 에러발생
var Cho: Man = Man(yourage:2, yourweight:20.5, "actor")
Cho.display() //나이:2 몸무게:20.5 직업:actor
|
cs |
self 키워드는 현재 클래스 또는 메서드의 프로퍼티를 가리킬 때 사용
생성자는 여러개 정의 할 수 있습니다. (오버로딩: 매개변수가 다르면 서로다른 메서드로 취급)
Failable initializer
생성자에 잘못된 값을 넣을 경우를 대비하여 옵셔널 타입객체를 리턴하는 생성자 (실패시 nil을 반환)
class Man{
var age: Int
var kg_w: Double
var job:String = "jobless"
func display(){
print("나이:\(age), 몸무게(kg):\(kg_w), 직업:\(job)")
}
init?(age:Int, weight:Double, _ yourjob:String){
if(age <= 0 || weight <= 0){
return nil
}
else{
self.age = age
kg_w = weight
}
job = yourjob
}
}
var Kim: Man = Man(age:0, weight:17.5, "actor")!
// age가 0이므로 nil 리턴
// 강제 언래핑을 하면 nil을 언래핑할 수 없으므로 crash 발생
if let Park = Man(age:20, weight:56.9, "police"){
Park.display() //나이:20, 몸무게(kg):56.9, 직업:police
} // 안전한 언래핑
|
cs |
소멸자
본문1
상속과 프로토콜
클래스는 단 하나의 부모 클래스만 상속 가능
프토로콜은 여러개를 채택할 수 있다. (클래스, 구조체, 열거형 모두 가능)
super
부모 메서드를 호출할 때 사용
자식클래스에 프로퍼티가 추가되면 해당 프로퍼티까지 초기화 하거나 init()추가 필요
extension
이미 구현했던 클래스, 구조체, 열거형, 프로토콜에 새로운 기능을 추가하는 것
자식클래스를 생성 혹은 참조하지 않고 기존 클래스에 메서드,생성자 computed프로퍼티 등을 추가할 때 이용
기존에 정의된 Double구조체에 squared, half 메서드를 추가
extension Double{ //표준자료형인 Double
var squared : Double{
return self * self
}
func half(num:Double) -> Double{
return num / 2
}
}
let myValue:Double = 3.0
print(myValue.squared) //9.0
print(2.0.squared) //4.0
print(2.0.squared * 2.0)//8.0
print(3.0.half(num:7.0))//3.5
|
cs |
접근제어
모듈: 코드배포의 단일유닛 [앱, 프레임웍, 외부라이브러리 등이 될 수 있음]
접근 수정자 | 접근범위 |
open | public과 범위동일, (클래스, 클래스멤버에만 사용됨) |
public | 현재 모듈의 모든 소스파일 + 모듈 외부의 소스파일 |
internal | 현재 모듈의 모든 소스파일 |
fileprivate | 현재 소스파일 |
private | 현재 블록 (인스턴스, 서브클래스도 접근불가) |
프로토콜
자바의 인터페이스와 비슷한 역할, 프로퍼티, 메서드 선언의 집합
프로토콜을 채택하는 클래스,구조체, 열거형, extension 은 선언된 메서드를 구현하여 프로토콜을 준수해야함
protocol Talkable {
var first:String {get}
var totalLang:Int {get set}
func printLang()
}
|
cs |
프로토콜에서의 var는 변수의 가변성 여부와는 관계없습니다
get과 set은 선언된 프로퍼티가 최소한으로 지켜야할 사항입니다
{get}은 읽기만 구현해도 되지만 읽기,쓰기 모두 구현해도 좋습니다
즉, first는 let뿐만 아니라 var로도 선언가능하며 totalLang은 var로만 선언할 수 있습니다
protocol은 최소한의 의무사항 이기 때문입니다
위의 프로토콜을 준수한 클래스는 아래와 같습니다
class korean:Talkable{
var first = "한국어" //읽기+쓰기 구현
var totalLang:Int = 1
func printLang(){
print("\(first)포함 \(totalLang)개국어 가능")
}
init(totalLang:Int){
self.totalLang = totalLang
}
}
|
cs |
위를 보시면 클래스 상속과 프로토콜 채택을 구별할 수 없습니다
클래스가 가장 먼저 쓰이고 그 뒤에 프로토콜이 오게 됩니다
아래의 프토토콜 네이밍 특징으로 짐작만 할 수 있습니다
프로토콜 특징: -Delegate, -DataSource
프로퍼티 요구는 저장프로퍼티 뿐만 아니라 연산 프로퍼티로도 준수가 가능합니다
class korean:Talkable{
var first:String { return "한국어" }
var totalLang:Int = 1
func printLang(){
print("\(first)포함 \(totalLang)개국어 가능")
}
init(totalLang:Int){
self.totalLang = totalLang
}
}
|
cs |
프로토콜은 부모 프토토콜을 여러개 상속받을 수 있습니다
protocol A {
func printA ()
}
protocol B {
func printB()
}
protocol C:A,B {
func printC()
}
class ABC : C { // 프토콜 A,B를 준수하지 않아 에러발생
func printC(){
print("C")
}
}
|
cs |
올바른 예시
class ABC : C {
func printA(){
print("A")
}
func printB(){
print("B")
}
func printC(){
print("C")
}
}
|
cs |
클래스+프로토콜 혼합
protocol B{
func bb(num:Int) -> Int
}
class C {
func bb(num:Double)->Double{
return num
}
func bb(num:Int) -> Int{
return num
}
}
class A:C,B{ // C상속, B채택
override func bb(num:Int) -> Int {//오버라이드 + 프로토콜 준수
return num * 2
}(클래스C에서 func bb가 이미구현되어 있으므로 구현필수는 아님)
}
class D:A{ //A가 B프로토콜을 준수했기 때문에 B를 채택할 수 없다
override func bb(num:Int) -> Int{//오버라이드
return num * 3
}
}
var a:A = A()
print(a.bb(num:3)) //6
print(a.bb(num:3.0))//3.0
var d:D = D()
print(d.bb(num:5)) //15
|
cs |
열거형
관련있는 데이터(멤버)로 구성되어 있는 자료형 객체 (-중 하나만 고를 수 있다)
잘못된 데이터 입력방지에 목적이 있습니다
enum Compass {
case North, South, East, West
}
print(Compass.North) // North
print(type(of:Compass.West)) // Compass
|
cs |
참고자료
한성현 교수님의 유튜브강의 (https://www.youtube.com/channel/UCM8wseo6DkA-D7yGlCrcrwA)
야곰님의 유튜브 강의
'🍎iOS프로그래밍 > 겨울방학 특강' 카테고리의 다른 글
Swift문법 - Generic (0) | 2022.01.08 |
---|---|
Swift문법 - error handling (0) | 2022.01.08 |
Swift문법 - 옵셔널 체이닝 (0) | 2022.01.07 |
Swift문법 - 열거형,구조체 (0) | 2022.01.06 |
[복습] Swift문법 간단 정리-1 (0) | 2022.01.04 |
댓글