import UIKit
import WebKit

class WebViewController: UIViewController {
    @IBOutlet weak var webView: WKWebView!
    
    @IBAction func goWeb(_ sender: UISegmentedControl) {
        if sender.selectedSegmentIndex == 0 {
            let myURL = URL(string:"https://www.naver.com")
            let myRequest = URLRequest(url: myURL!)
            webView.load(myRequest)
        } else {
            let myURL = URL(string:"https://www.daum.net")
            let myRequest = URLRequest(url: myURL!)
            webView.load(myRequest)
        }
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        let myURL = URL(string:"https://aaaa.tistory.com/")
        let myRequest = URLRequest(url: myURL!)
        webView.load(myRequest)
        

        // Do any additional setup after loading the view.
    }
    
    @IBAction func goNaver(_ sender: UIButton) {
        let myURL = URL(string:"https://www.google.com")
        let myRequest = URLRequest(url: myURL!)
        webView.load(myRequest)
    }
}
---------------------------------------------------------------------------------
import UIKit
import WebKit

class WebViewController: UIViewController {
    @IBOutlet weak var webView: WKWebView!

    override func viewDidLoad() {
        super.viewDidLoad()
        loadInitialWebPage()
    }

    @IBAction func segmentedControlChanged(_ sender: UISegmentedControl) {
        let selectedURLString = sender.selectedSegmentIndex == 0 ? "https://www.naver.com" : "https://www.daum.net"
        loadWebPage(urlString: selectedURLString)
    }

    @IBAction func goGoogle(_ sender: UIButton) {
        loadWebPage(urlString: "https://www.google.com")
    }

    private func loadInitialWebPage() {
        let initialURLString = "https://aaaa.tistory.com/"
        loadWebPage(urlString: initialURLString)
    }

    private func loadWebPage(urlString: String) {
        if let url = URL(string: urlString) {
            let request = URLRequest(url: url)
            webView.load(request)
        }
    }
}

 리팩토링 전 소스코드와 ChatGPT를 통한 리팩토링 후 소스코드

 

'iOS' 카테고리의 다른 글

iOS(11-28)  (1) 2023.11.28
iOS (?)  (0) 2023.11.14
iOS (10)  (0) 2023.11.07
iOS (5)  (1) 2023.10.17
iOS (3)  (1) 2023.09.26

세그먼트 인덱스 값마다 설정할 수 있다

세그먼트 컨트롤러 추가부분, ctrl + 드래그로 해당 창을 띄울 수 있다

세그웨이를 설정하여 연결할 수 있다

 

Swift 파일을 추가하는데 표시된 부분은 부모 클래스를 지정하는 부분이다

Mp4 파일을 추가하는데 Add to targets 에 체크 해주어야 한다.

 

Path 는 Optional String 

'iOS' 카테고리의 다른 글

iOS(12_05)  (0) 2023.12.05
iOS (?)  (0) 2023.11.14
iOS (10)  (0) 2023.11.07
iOS (5)  (1) 2023.10.17
iOS (3)  (1) 2023.09.26

해당 자료: Do it! 스위프트로 아이폰 앱 만들기 입문, 송호정, 이범근 저,이지스퍼블리싱, 2023년 01월 20일

 

AppDelegate.swift

AppDelegate.swift은 iOS 앱의 핵심 파일 중 하나입니다. 이 파일은 앱의 생애주기(lifecycle)를 관리하고 앱의 전역적인 동작을 조정하는 역할을 합니다. 

  1. 앱의 시작과 종료를 관리합니다: AppDelegate는 앱이 처음 시작될 때 호출되는 application(_:didFinishLaunchingWithOptions:) 메서드를 포함하고 있습니다. 이 메서드는 앱이 구동되는 초기 설정을 수행하고, 앱이 백그라운드에서 실행되는 동안 발생하는 이벤트를 처리합니다. 또한 앱이 종료될 때 호출되는 applicationWillTerminate(_:) 메서드를 통해 앱이 종료되기 전에 필요한 작업을 처리할 수 있습니다.
  2. 상태 변화를 관리합니다: 앱이 활성화되거나 비활성화될 때 발생하는 이벤트를 처리하는 메서드를 제공합니다. 예를 들어, 앱이 백그라운드로 이동할 때 호출되는 applicationDidEnterBackground(_:) 메서드는 앱이 백그라운드에서 실행되는 동안 필요한 작업을 처리할 수 있도록 합니다. 반대로, 앱이 다시 활성화될 때 호출되는 applicationWillEnterForeground(_:) 메서드는 앱이 다시 활성화될 때 필요한 작업을 처리할 수 있도록 합니다.
  3. 알림과 디바이스 이벤트 관리: AppDelegate는 푸시 알림, 로컬 알림 등과 같은 알림 이벤트를 처리하기 위한 메서드를 제공합니다. 또한 디바이스의 회전, 터치 등과 같은 이벤트에 대한 처리도 담당합니다.
  4. 다른 시스템 이벤트 관리: AppDelegate는 앱이 다른 시스템 이벤트에 응답할 수 있도록 합니다. 예를 들어, 앱이 백그라운드에서 실행 중인 동안 전화가 왔을 때 호출되는 application(_:didReceiveRemoteNotification:fetchCompletionHandler:) 메서드는 푸시 알림을 처리할 수 있도록 합니다.

이러한 기능들을 통해 AppDelegate.swift 파일은 앱의 전반적인 동작을 관리하고, 앱의 핵심 로직과 UI 요소들 사이의 연결 역할을 수행합니다.

 

SceneDelegate.swift

SceneDelegate.swift 파일은 iOS 13 이후 도입된 개념인 'Scene'와 관련된 기능을 처리합니다.

'Scene'은 앱의 사용자 인터페이스와 관련된 모든 데이터와 상태를 포함하는 객체로서, 여러 개의 'Scene'을 이용해 앱이 여러 개의 사용자 인터페이스를 동시에 관리하게 할 수 있습니다. 이를 통해 멀티 윈도우 사용이 가능해집니다. SceneDelegate.swift 파일에서는 주로 다음과 같은 기능을 처리합니다:

1. Scene의 생명주기 관리: Scene이 생성되거나 소멸될 때, 또는 활성화 또는 비활성화 될 때 호출되는 메서드들을 정의합니다. 예를 들어 `sceneDidBecomeActive(_:)` 메서드는 Scene이 활성화될 때 호출되며, `sceneDidEnterBackground(_:)` 메서드는 Scene이 백그라운드로 들어갈 때 호출됩니다.

2. 사용자 인터페이스 설정: `scene(_:willConnectTo:options:)` 메서드에서는 앱의 사용자 인터페이스를 설정합니다. 이 메서드는 Scene이 처음 만들어질 때 호출되며, 주로 초기 ViewController를 설정하는데 사용됩니다.

3. 상태 복원: `stateRestorationActivity(for:)` 및 `scene(_:willContinueUserActivityWithType:)` 같은 메서드를 통해 앱의 상태 복원을 관리할 수 있습니다. 이 기능은 앱이 중단된 후 다시 시작될 때 이전의 상태를 복원하는 데 사용됩니다.

4. 외부 액션 처리: `scene(_:openURLContexts:)` 메서드를 통해 앱이 외부에서 전달받은 URL을 처리할 수 있습니다. 이 기능은 다른 앱으로부터 데이터를 전달받아 처리하는 데 사용됩니다. 따라서 SceneDelegate.swift는 앱의 여러 Scene들의 생명주기를 관리하고, 사용자 인터페이스를 설정하고, 상태 복원을 처리하고, 외부 액션을 처리하는 등의 역할을 합니다.

 

import Foundation
func calcBMI(weight : Double, height : Double) -> String{
let bmi = weight / (height*height*0.0001) // kg/m*m
let shortenedBmi = String(format: "%.1f", bmi)
var body = ""
if bmi >= 40{
body = "3단계 비만"
} else if bmi >= 30 && bmi < 40 {
body = "2단계 비만"
} else if bmi >= 25 && bmi < 30 {
body = "1단계 비만"
} else if bmi >= 18.5 && bmi < 25 {
body = "정상"
} else {
body = "저체중"
}
return "BMI:\(shortenedBmi), 판정:\(body)"
}
print(calcBMI(weight:62.5, height: 172.3))

함수를 사용한 BMI 계산기

 

// bmiMode.swift
import Foundation
class BMI {
    var weight : Double
    var height : Double
    init(weight:Double, height:Double){
        self.height = height
        self.weight = weight
    }
    func calcBMI() -> String {
        let bmi=weight/(height*height*0.0001)// kg/m*m
        let shortenedBmi = String(format: "%.1f", bmi)
        var body = ""
        if bmi >= 40{
            body = "3단계 비만"
        } else if bmi >= 30 && bmi < 40 {
            body = "2단계 비만"
        } else if bmi >= 25 && bmi < 30 {
            body = "1단계 비만"
        } else if bmi >= 18.5 && bmi < 25 {
            body = "정상"
        } else {
            body = "저체중"
        }
        return "BMI:\(shortenedBmi), 판정:\(body)"
    }
}
var han = BMI(weight:62.5, height:172.3)
print(han.calcBMI())

클래스를 활용한 BMI 계산기

 

'iOS' 카테고리의 다른 글

iOS(12_05)  (0) 2023.12.05
iOS(11-28)  (1) 2023.11.28
iOS (10)  (0) 2023.11.07
iOS (5)  (1) 2023.10.17
iOS (3)  (1) 2023.09.26
import UIKit

var greeting = "Hello, playground"
let view = UIView()
view.frame = CGRect(x:0, y:0, width: 200, height: 100)
view.backgroundColor = .blue

 

Swift의 오류제어

 

브레이크 포인트

break point가 걸려있어서 제대로 실행이 되지않는 경우가 있다. 해당된 행의 파란색 태그를 오른쪽으로 드래그하여 해제할 수 있다.

 

해당오류 발생 시 오른쪽 상단 메뉴에서 해당된 라벨연결을 해제하는 것으로 해결 가능하다.

 

초기화 함수

 

앱 아이콘 적용

 

간단한 응용

 

'iOS' 카테고리의 다른 글

iOS(11-28)  (1) 2023.11.28
iOS (?)  (0) 2023.11.14
iOS (5)  (1) 2023.10.17
iOS (3)  (1) 2023.09.26
iOS (2)  (0) 2023.09.19

Swift의 closure 

func add(x: Int, y: Int) -> Int {
return(x+y)
}
print(add(x:10, y:20))


let addf = {  (x:Int, y:Int) -> Int in
return (x+y)
}

print(addf(x:3, y:4))
//--> print(addf(3,4)

//main.swift:11:11: error: extraneous argument labels 'x:y:' in call
//print(addf(x:3, y:4)

closure로 호출할 시에는 argument label이 필요하지 않습니다

 

func mul(a: Int, b: Int) -> Int {
    return a * b
}
let multiply = {(a: Int, b: Int) -> Int in
    return a * b
}
print(mul(a:10, b:20))
print(multiply(10, 20))

let add = {(a: Int, b: Int) -> Int in
    return a + b
}
print(add(10, 20)) 

func math(x: Int, y: Int, cal: (Int, Int) -> Int) -> Int {
    return cal(x, y)
}
var result = math(x: 10, y: 20, cal: add) //return add(10,20)
print(result)
result = math(x: 10, y: 20, cal: multiply)//return multiply(10,20)
print(result)
result = math(x: 10, y: 20, cal: {(a: Int, b: Int) -> Int in
    return a + b
}) //클로저 소스를 매개변수에 직접 작성
print(result)
result = math(x: 10, y: 20) {(a: Int, b: Int) -> Int in
    return a + b
}//trailing closure
print(result)

후행 클로저(trailing closure)

 클로저가 함수의 마지막 argument라면 마지막 매개변수명(cl)을 생략한 후 함수 소괄호 외부에 클로저를 작성

func someFun(cl: () -> Void) {
}
// trailing closure를 사용 안하면
someFun(cl: {
//closure’s body
})
// trailing closure 사용
someFun() {
//trailing closure's body goes here
}

func math(x: Int, y: Int, cal: (Int, Int) -> Int) -> Int {
return cal(x, y)
}

result = math(x: 10, y: 20) {(a: Int, b: Int) -> Int in
return a + b
}//trailing closure

 

closure 표현식의 생략

result = math(x: 10, y: 20, cal: {(val1: Int, val2: Int) in
	return val1 + val2
}) //리턴형 생략
print(result)

result = math(x: 10, y: 20) {(val1: Int, val2: Int) in
	return val1 + val2
} //trailing closure, 리턴형 생략
print(result)

result = math(x: 10, y: 20, cal: {
	return $0 + $1
}) //매개변수 생략하고 단축인자(shorthand argument name)사용
print(result)

result = math(x: 10, y: 20) {
	return $0 + $1
} //trailing closure, 매개변수 생략하고 단축인자사용
print(result)

result = math(x: 10, y: 20, cal: {
	$0 + $1
}) //클로저에 리턴값이 있으면 마지막 줄을 리턴하므로 return생략
print(result)

result = math(x: 10, y: 20) { $0 + $1 } //return 생략
print(result)

 

 property는 저장 프로퍼티(stored property)과 계산 프로퍼티(computed property)

class Man{
	var age : Int = 1 //stored property는 초기값이 있어야 함
	var weight : Double = 3.5
}

class Man{
	var age : Int? //stored property는 초기값이 있어야 함, nil
	var weight : Double!
}

class Man{
	var age : Int = 1
	var weight : Double = 3.5
	func display(){
	print("나이=\(age), 몸무게=\(weight)")
	}
class func cM(){
	print("cM은 클래스 메서드입니다.")
	}
static func scM(){
	print("scM은 클래스 메서드(static)")
	}
}

var kim : Man = Man()
kim.display() //인스턴스 메서드는 인스턴스가 호출
Man.cM() //클래스 메서드는 클래스가 호출
Man.scM() //클래스 메서드는 클래스가 호출

 클래스명.클래스메서드()

 타입 메서드 또는 클래스 메서드는 클래스 레벨에서 동작

 타입 메서드는 인스턴스 메서드와 동일한 방법으로 선언하지만 class 나 static 키워드를 앞에 붙여서 선언

 class키워드로 만든 클래스 메서드는 자식 클래스에서 override가능 함

----------------------------------------------------------------------------------------------------------------------------------------------

class Man{
var age : Int = 1  // init 초기화 시 초기값 생략가능
var weight : Double = 3.5 // init 초기화 시 초기값 생략가능
func display(){
	print("나이=\(age), 몸무게=\(weight)")
}
init(age: Int, yourWeight : Double){
	self.age = age  // this 대신 self 사용가능
	weight = yourWeight
	} //designated initializer
}
//var kim : Man = Man() //오류
//init()을 하나라도 직접 만들면 default initializer는 사라짐
var kim : Man = Man(age:10, yourWeight:20.5)
kim.display()

 클래스, 구조체, 열거형(enum) 인스턴스가 생성되는 시점에서 해야 할 초기화 작업

 인스턴스가 만들어지면서 자동 호출됨

 init 메서드(생성자)

      init() { }

 designated initializer

 - 모든 프로퍼티(age, weight)를 다 초기화시키는 생성자

 init()을 하나라도 직접 만들면 기본적으로 만들어지는 눈에 안보이는 default initializer는 사라짐

 소멸자

 - 인스턴스가 사라질 때 자동 호출

 - deinit{}

-----------------------------------------------------------------------------------------------------------------------------------------------------------------

class Man{
var age : Int = 1
var weight : Double = 3.5
func display(){
        print("나이=\(age), 몸무게=\(weight)")
    }
init(age: Int, weight : Double){
        self.age = age
        self.weight = weight
    } //designated initializer
init(age:Int) // 메소드 오버로딩
    {
        self.age=age
    }
}
//var kim : Man = Man() //오류
//init()을 하나라도 직접 만들면 default
//initializer는 사라짐
var kim : Man = Man(age:10, weight:20.5)
kim.display()

 매개변수의 개수와 자료형이 다른 같은 이름의 함수를 여러 개 정의

 매개변수가 다른 두 생성자를 통해 두가지 방법으로 인스턴스를 만들 수 있음

'iOS' 카테고리의 다른 글

iOS (?)  (0) 2023.11.14
iOS (10)  (0) 2023.11.07
iOS (3)  (1) 2023.09.26
iOS (2)  (0) 2023.09.19
2023-09-12  (0) 2023.09.12
for var i = 0; i < 10; i+=1 
{ // for i in 0..<10 로 수정해야 함
print(i)
}
-------------------------------------
for var i in 0..<10
{
    print(i)
}
----------------------------------
for _ in 0..<5  // _  <- 사용 가능
{
    print("Han")
}
-------------------------------------
let name = ["a","b","c","d"]
for i in name[2...]
{
    print(i)
}
----------------------------------------------------------
let numberOfLegs = ["Spider": 8, "Ant": 6, "Dog": 4]
//dictionary는 key:value형식의 배열
for (animalName, legCount) in numberOfLegs 
{
    print("\(animalName)s have \(legCount) legs")
}
-------------------------------------
// 감소하는 경우
for i in (5..<0).reversed()
{
    print(i)
}
-------------------------------------
// 2씩 증가하는 경우
for i in stride(from: 0, to: 10, by: 2) 
{
    print(i)
}
-------------------------------------

다른 언어들과 다른 Swift의 for문 사용법...

 

for i in 1..<10 
{
if i > 5 break
//error: expected '{' after 'if' condition
print(i)
}

Swift에선 조건식 다음 한 줄만 있어도  { } 중괄호를 사용해야 한다.

 

var a = 1
var b = 2
var c = 3
var d = 4
if a < b && d > c {
print("yes")
}
if a < b, d > c { 
print("yes")
}

Swift if문에서  ,(콤마)를 사용할 경우 AND와 동일하다

 

let someCharacter: Character = "z"
switch someCharacter 
{
case "a":
	print("The first letter of the alphabet")
case "z":
	print("The last letter of the alphabet")
default:
	print("Some other character")
}
-------------------------------------------------
let anotherCharacter: Character = "a"
switch anotherCharacter 
{
case "a", "A":
	print("A 글자")
default:
	print("A글자 아님")
}
----------------------------------------------------
let weight = 60.0
let height = 170.0
let bmi = weight / (height*height*0.0001) // kg/m*m
var body = ""
switch bmi {
case 40...:
    body = "3단계 비만"
case  30..<40:
    body = "2단계 비만"
case 25..<30: 
    body = "1단계 비만"
case 18.5..<25:
    body = "정상"
default:
    body = "저체중"
}
print("BMI:\(bmi), 판정:\(body)")

Switch~Case 문, break문이 포함되어 있다.

Switch~Case 문에서 ,(콤마)는 OR와 동일하다

Switch~Case 문에서도 범위지정 매칭을 사용할 수 있다.

 

var temperature = 60
switch (temperature)
{
case 0...49 where temperature % 2 == 0:
	print("Cold and even")
case 50...79 where temperature % 2 == 0:
	print("Warm and even")
case 80...110 where temperature % 2 == 0:
	print("Hot and even")
default:
	print("Temperature out of range or odd")
}

where절은 다양한 식에 부가적인 조건을 추가하기 위하여 사용한다

값이 속하는 범위뿐만 아니라 그 숫자가 홀수인지 짝수인지도 검사

 

var value = 4
switch (value)
{
case 4:
	print("4")
	fallthrough
case 3:
	print("3")
	fallthrough
case 2:
	print("2")
	fallthrough
default:
	print("1")
}

내장되어 있는 break문에 걸리지않고 순차적으로 실행되기 위해선 fallthrough 이라는 키워드를 사용하면 된다

 

func sayHello() 
{ //리턴값 없으면( -> Void ) 지정하지 않아도 됨
	print("Hello")
}
func message(name: String, age: Int) -> String 
{
	return("\(name) \(age)")
}

func add(first x: Int, second y: Int) -> Int {
//외부 내부:자료형,외부 내부:자료형 -> 리턴형
	return(x+y) 
}
add(first:10, second:20)
-----------------------------------------------------------------
func add(x:Int, y:Int) -> Int{
    return (x+y)
}

print(add(x:10,y:10))

리턴값은 -> 이후에 작성한다

함수 선언 시 외부 내부:자료형, 외부 내부:자료형 -> 리턴형

함수 정의할 때는 내부 매개변수명을 사용한다

함수 호출할 때는 외부 매개변수명을 사용한다

------------------------------------------------------------------------------------------------------------

외부 매개변수명 생략하면 내부 매개변수명이 외부 매개변수명까지 겸한다

 

func add(_ x: Int, _ y: Int) -> Int {
	return(x+y) 
}
print(add(1,2))
print(type(of:add))

( _ ) 사용시 외부 매개 변수명을 생략할 수 있다.

 

func add(_ x: Int, with y: Int) -> Int {
	return(x+y) 
}
print(add(1,with:2))
print(type(of:add))

첫번째 외부 매개 변수만 생략하는 경우이다. Object-c 의 방식이며 가장 많이 사용되는 방식이다.

'iOS' 카테고리의 다른 글

iOS (?)  (0) 2023.11.14
iOS (10)  (0) 2023.11.07
iOS (5)  (1) 2023.10.17
iOS (2)  (0) 2023.09.19
2023-09-12  (0) 2023.09.12

- Optional

Swift에서 Optional은 값이 있을 수도, 없을 수도 있는 상황을 표현하기 위해 사용됩니다. 이는 Swift의 안전성(safety)에 중점을 둔 설계의 일부입니다.

Optional은 다음과 같은 상황에서 유용합니다:

  1. 값이 없는 상황 표현: 변수나 함수가 값을 반환하지 않는 경우를 안전하게 처리할 수 있습니다. 예를 들어, 딕셔너리에서 키로 값을 조회할 때 해당 키가 존재하지 않으면 nil을 반환합니다.
  2. 초기화되지 않은 상태 표현: 객체의 초기화 과정에서 일부 속성 값이 즉시 사용 가능하지 않거나 나중에 설정될 수 있어야 하는 경우 Optional을 사용할 수 있습니다.
  3. 옵셔널 체이닝(Optional Chaining): 옵셔널 체이닝은 옵셔널에 포함된 하위 속성에 접근하려 할 때 nil 검사를 반복적으로 해야 하는 번거로움을 줄여줍니다.
  4. 옵셔널 바인딩(Optional Binding): if-let 또는 while-let 구문과 함께 사용하여 옵셔널의 값을 안전하게 추출할 수 있습니다.
  5. 옵셔널 강제 추출(Forced Unwrapping): 개발자가 확신할 때만 사용해야 합니다. 값이 없다면(runtime 시점에) 앱 크래시를 유발합니다.
  6. nil 병합 연산자(Nil-Coalescing Operator): 옵셔널 값이 nil인 경우 기본값(default value)을 제공하는 방법입니다.

Optional 없이 모든 것들을 처리하려고 하면 앱 크래시와 같은 문제가 발생할 가능성이 많아집니다. 따라서 Swift는 이러한 문제들로부터 개발자와 사용자를 보호하기 위해 Optional 개념을 도입했습니다.

 

var x : Int?
x = 10
print(x)
//Optional(10)

- Optional형은 초기값이 없다면 nil 값이 들어가고 값을 대입해준다 하여도 Optional( ) 으로 랩핑된다

 

var x : Double = 10.0
var y : Int = Int(x)

print(Int("123"))
print(Int("hi))

//Optional(123)
//nil
var x : Int? //옵셔널 정수형 변수 x 선언
var y : Int = 0
x = 10 // 주석처리하면?
print(x) // Optional(10)
print(x!) // nil값일때 unwrapping 시 오류발생
print(y)
x = x!+2 
y = x! //가능?

강제 추출 연산자 !는 피연산자와 꽉 묶이는(tightly associates) 높은 우선순위를 가진다.

즉, 대부분의 다른 연산자보다 먼저 계산되며, 다른 연산자와 함께 사용되는 표현식에서는 피연산자에 밀접하게(bind tightly) 결합되어, 표현식에서 다른 연산자와는 무관하게 즉시 적용된다.

예를 들어, let x = optionalValue! + 5 표현식에서 강제 추출 연산자 !는 덧셈 연산자 +보다 높은 우선순위를 가지므로, 옵셔널 값이 5에 더해지기 전에 먼저 추출된다. 그러나 옵셔널 값이 nil인 경우 런타임 오류가 발생할 수 있으므로, 가능한한 강제 추출 대신 옵셔널 바인딩 또는 옵셔널 체인을 사용하는 것이 좋다. 이렇게 하면 코드를 보다 견고하게 만들어 crash를 피할 수 있다

 

- 강제 언래핑하는 또 다른 방법으로, 옵셔널 바인딩(optional binding)을 이용하여 옵셔널에 할당된 값을 임시 변수 또는 상수에 할당

if let constantname = optionalName{
//옵셔널 변수가 값이 있다면 언래핑해서 일반 상수 constantname에 대입하고 if문 실행
//값이 없다면 if문의 조건이 거짓이 되어 if문을 실행하지 않음
}
if var variablename = optionalName {
//옵셔널 변수가 값이 있다면 언래핑해서 일반 변수 variblename에 대입하고 if문 실행
//값이 없다면 if문의 조건이 거짓이 되어 if문을 실행하지 않음
}
var x : Int?
x = 10
if let xx = x { //옵셔널 변수 x가 값(10)이 있으므로 언래핑해서 일반 상수 xx에 대입하고 if문 실행
print(x,xx)
}
else {
print("nil")
}
var x1 : Int?
if let xx = x1 { //옵셔널 변수 x1이 값이 없어서 if문의 조건이 거짓이 되어 if문 실행하지 않고 else로 감
print(xx)
}
else {
print("nil")
}

 여러 옵셔널 변수를 한번에 언래핑하는 방법은 콤마 사용

var pet1: String?
var pet2: String?
pet1 = "cat"
pet2 = "dog"
if let firstPet = pet1, let secondPet = pet2
{
print(firstPet, secondPet)
}
else 
{
print("nil")
}

 

- Implicitly Unwrapped Optional

  • 형 다음에 ?가 아닌 !를 쓰는 옵셔널 형 // Int!, String!
  • When you use an implicitly unwrapped optional value, Swift first tries to use it as an ordinary optional value; if it can’t be used as an optional, Swift force-unwraps the value.
  • 일반 옵셔널 값으로 사용하려고 하지만, optional로 사용할 수 없는 경우 Swift는 값을 강제로 품
  • Optional로 사용되지 않으면 자동으로 unwrap함

- 두 가지 Optional 형 : Int? vs Int!

let x : Int? = 1
let y : Int = x!
let z = x
print(x,y,z) //Optional(1) 1 Optional(1)
print(type(of:x),type(of:y),type(of:z))
//Optional<Int> Int Optional<Int>
let a : Int! = 1 //Implicitly Unwrapped Optional
let b : Int = a //Optional로 사용되지 않으면 자동으로 unwrap함
let c : Int = a!
let d = a //Optional로 사용될 수 있으므로 Optional형임
let e = a + 1 
print(a,b,c,d,e) //Optional(1) 1 1 Optional(1) 2
print(type(of:a),type(of:b),type(of:c),type(of:d), type(of:e))
//Optional<Int> Int Int Optional<Int> Int

Nil-Coalescing Operator (Nil합병연산자) ??

  • 옵셔널변수 ?? nil일 때 할당되는 값
  • 옵셔널 변수의 값이 nil이면 ?? 다음 값으로 할당됨
  • 옵셔널 변수의 값이 nil이 아니면 언래핑된 값이 나옴
let defaultAge = 1
var age : Int?
//age = 3
print(age) // optional(3)
var myAge = age ?? 1
//age가 nil이 아니므로 언래핑된 값이 나옴
print(myAge) // 3

 

 

- Swift에서 Optional 값을 처리하는 방법은 여러 가지가 있습니다. 이는 옵셔널 값이 nil일 수도 있다는 것을 명시적으로 표현하고, 이를 안전하게 처리할 수 있는 방법을 제공합니다. (GPT에서 발췌)

  1. 강제 추출 (Forced Unwrapping): 옵셔널 변수 뒤에 느낌표 (!)를 붙여서 값을 강제로 추출합니다. 값이 nil인 경우에는 런타임 에러가 발생하므로 사용에 주의해야 합니다.
  2. swift
    let optionalInt: Int? = 10
    let forcedUnwrappedInt: Int = optionalInt!
    
  3. 옵셔널 바인딩 (Optional Binding): if-let 또는 guard-let 구문을 사용하여 안전하게 옵셔널 값을 추출할 수 있습니다.
  4. swift
    // if-let 사용 예시
    if let unwrappedInt = optionalInt {
        print(unwrappedInt)
    }
    
    // guard-let 사용 예시
    guard let unwrappedInt = optionalInt else {
        return 
    }
    
    print(unwrappedInt)
    
  5. Nil 병합 연산자 (Nil-Coalescing Operator): ?? 연산자를 사용하여 옵셔널 값이 nil일 경우 기본값을 제공할 수 있습니다.
  6. swift
    let nonOptionalValue = optionalValue ?? defaultValue 
    
  7. 옵셔널 체이닝 (Optional Chaining): 옵셔널 값에 접근하는 연산 중 어느 하나라도 실패(nil)한다면 전체 표현식은 실패(nil)를 반환합니다.
  8. swift
    let lengthOfFirstName = user.firstName?.count 
    
  9. 맵(Map)과 플랫맵(FlatMap) 함수를 활용한 안전한 변환 및 추출:
  • map 함수는 옵셔널 값이 존재하는 경우 해당 값을 변환한 후 다시 옵셔널로 감싸서 반환합니다.
  • flatMap 함수는 map과 비슷하지만, 결과값을 다시 감싸지 않아 중첩된(optional of optional) 형태를 방지합니다.
  1. Implicitly Unwrapped Optionals: 앱의 생명주기 동안 한번 초기화된 후 nil이 아니라고 확신할 수 있는 상황에서 사용됩니다. 일반 변수처럼 사용 가능하지만, 실제로는 Optional입니다.

위와 같은 방법들을 통해 Swift에서는 옵셔널 값을 안전하게 처리할 수 있습니다. 이를 통해 런타임 에러를 방지하고, 코드의 안정성을 높일 수 있습니다.

---------------------------------------------------------------------------------------------

- Swift 연산자

1 (높음) as?, as! 왼쪽으로
2 is, as 왼쪽으로
3 ., (function call), (subscript), (postfix ++, --) , (force unwrap) 왼쪽으로
4 (높음) - (negation),! (logical NOT) , (prefix ++, --) , ~ 오른쪽으로
5 *,/,%,&,<<,>> 왼쪽으로
6 +,-,&^ (왼쪽으로)
7 (비교연산자들): <,<=,= = ,!= ,> = ,> ,(pattern match): ~=,(type check): is, as?, as!

 x++ // x를 1 증가시킴, Swift 3에서 없어짐, x+=1

 x-- // x를 1 감소시킴, Swift 3에서 없어짐, x-=1

 

var a = 2
var b = 2.0

print(a/b);
print(a+b);

//main.swift:4:8: error: binary operator '/' cannot be applied to operands of type 'Int' and 'Double' print(a/b);

 - 같은 자료형이 아니면 연산이 불가능하다

 

---------------------------------------------------------------------------------------------

- 형변환과 타입 검사

 

 as로 upcasting : 자식인스턴스를 부모클래스로 변환

  • 상속 관계가 있는 클래스들끼리만타입 캐스팅 가능
  • 자식(부모로부터상속받아 더 많은 것을 가지고 있음)인스턴스를부모로 캐스팅하는 것은 문제가 없음
  • as 연산자를 이용한 타입 변환(type casting)
  • 자식인스턴스 as 부모클래스 // upcasting 안전한 캐스팅. 자식이 추상화됨  업캐스팅은 객체를 부모 클래스의 객체로 형 변환
  • 형 변환은 성공할 것이기 때문에 보장된 변환(guaranteed conversion)
  • UIButton은UIControl의자식 클래스이므로 안전하게 형 변환
  • let myButton: UIButton = UIButton()
  • let myControl = myButton as UIControl //자식인스턴스 as 부모 클래스
  • 자식인스턴스인 myButton을 부모 클래스형으로 형 변환

as! as?로 downcasting:부모인스턴스를 자식클래스로 변환

  • 다운캐스팅은 부모 인스턴스를 자식 클래스로 변환하는 데 사용
  • 성공 확신이 있으면 as! 키워드를 사용하며 강제 변환(forced conversion)
  • 변환이 안되면 crash
  • 성공 확신이 없으면 as?를 사용하여 안전하게 변환
  • 변환이 안되면 nil을 리턴하므로 옵셔널 타입으로 반환함
  • 부모인스턴스 as! 자식클래스 // downcasting 일반 타입으로 반환 /다운캐스팅이 반드시 성공할 것이라는 확신이 있을 때
  • 부모인스턴스 as? 자식클래스 // downcasting 옵셔널 타입으로 반환. 확신이 없을 경우

타입 검사

 타입 검사(type check)

let x = 1
if x is Int {
print("Int!")
}

 객체가 MyClass라는 이름의 클래스의 인스턴스인지 검사

 인스턴스가 해당 클래스인가?
 인스턴스 is 클래스
 if myobject is MyClass {
// myobject는 MyClass의 인스턴스이다
}
class A {}
let a = A()
if a is A{
print("Yes")
}

 

 

'iOS' 카테고리의 다른 글

iOS (?)  (0) 2023.11.14
iOS (10)  (0) 2023.11.07
iOS (5)  (1) 2023.10.17
iOS (3)  (1) 2023.09.26
2023-09-12  (0) 2023.09.12

https://bbiguduk.gitbook.io/swift/

 

The Swift Programming Language (한국어) - Swift

The Swift Programming Language (한국어)

bbiguduk.gitbook.io

Swift 공식문서 한글화 사이트

 

 

https://docs.swift.org/swift-book/documentation/the-swift-programming-language/revisionhistory/

 

Documentation

 

docs.swift.org

https://github.com/apple/swift-evolution

 

GitHub - apple/swift-evolution: This maintains proposals for changes and user-visible enhancements to the Swift Programming Lang

This maintains proposals for changes and user-visible enhancements to the Swift Programming Language. - GitHub - apple/swift-evolution: This maintains proposals for changes and user-visible enhance...

github.com

Swift의 변화과정들을  볼수있는 사이트

 

var x : Int = 10;

let y : Int = 20;
y = 30;
//error: cannot assign to value: 'y' is a 'let' constant

var z = 3;

print(x)
print(y)
print(z)

//main.swift:8:12: error: '=' must have consistent whitespace on both sides

let은 상수를 선언할때 사용되며

위와 같이 초깃값이 있을 경우에는 컴파일러가 타입 추론(type inference)을 하므로 데이터 타입을 명시할 필요 없다

 

print(1.0, 2.0, 3.0, 4.0, 5.0, separator: " ... ") // Prints "1.0 ... 2.0 ... 3.0 ... 4.0 ... 5.0"

for n in 1...5 { print(n, terminator: "") } // Prints "12345"

 

var x = 10
print(type(of:x))
let s = MemoryLayout.size(ofValue: x)//8
let t = MemoryLayout<Int>.size
print(s, t)

//Int
//8 8

swift 에서는 Int형의 크기가 8byte 이다

데이터타입의 크기들은 플랫폼에 따라 다르다. Int형을 예시로 들자면 대부분의 언어와 컴파일러에선 4Byte로 인식하여 사용하지만 Swift 같은 경우 Int형의 크기를 8Byte로 사용한다.

 

var x : Int = 10
print(x)
print("x")
print("\(x)")
print("값은 \(x)입니다.")
print("Int32 Min = \(Int32.min) Int32 Max = \(Int32.max)")


10
x
10
값은 10입니다.
Int32 Min = -2147483648 Int32 Max = 2147483647

 

원하는 값을 문자열로 출력하기 위해선 \( ) 를 사용한다

 

var userName : String = "Kim" // : String 생략하는 것이 일반적임
var age = 20
var message = "\(userName)의 나이는 \(age)입니다."
print(message) // Kim의 나이는 20입니다.

문자열 보간(string interpolation)을 사용하여 문자열과 변수, 상수, 표현식, 함수 호출의 조합으로 만들 수도 있다

 

타입 어노테이션(type annotation)

 Int 타입의 userCount 라는 이름의 변수를 선언

 var userCount : Int = 10 // : Int가 type annotation

 

선언부에 타입 어노테이션이 없으면 스위프트 컴파일러는 상수 또는 변수의 타입을 식별하기 위하여 타입 추론(type inference) 사용

 해당 상수 또는 변수에 값이 할당되는 시점에서 그 값의 타입을 확인하고 그와 같은 타입처럼 사용

 var signalStrength = 2.231 // var signalStrength : Double = 2.231

 let companyName = "My Company"

 signalStrength라는 변수를 Double 타입(스위프트의타입 추론에서 모든 부동 소수점 수는 Double 타입)

 companyName이라는 상수는 String 타입으로 간주

 

 

상수를 선언할 때도 타입 어노테이션을 사용하면 나중에 코드에서 값을 할당할 수 있다.

let bookTitle: String 
var book = true
if book { 
bookTitle = "iOS" 
}
else { 
bookTitle = "Android" 
} 
print(bookTitle)

 상수에는 값을 한 번만 할당할 수 있다

 

튜플은 Swift에서 가장 강력한 기능 중 하나이며 여러 값을 하나의 개체에 일시적으로 묶는 방법이다.

튜플에 저장되는 항목들은 어떠한 타입도 될 수 있으며, 저장된 값들이 모두 동일한 타입일 필요도 없다

let myTuple = (10, 12.1, "Hi")
var myString = myTuple.2
print(myString)
print(myTuple.1,myTuple.2,myTuple.0)

 

튜플을 생성할 때 각 값에 이름을 할당할 수도 있다

let myTuple = (count: 10, length: 12.1, message: "Hi")
let (myInt, myFloat, myString) = myTuple
print(type(of:myTuple))
print(myTuple.0, myTuple.count)

//(count: Int, length: Double, message: String)
//10 10

 

Void는 빈 튜플(empty tuple) 이다

typealias Void = () //아무 내용도 없는 튜플,

typealias name = existing_type

 

Optional(옵셔널)은 값이 존재하지 않을 수 있는 상황을 다루기 위한 개념으로 다양한 프로그래밍 언어에서 지원됩니다.

var x : Int = 10
var y : Int?
var z : Int!
print(x,y,z)
//10 nil nil
var x : Int = 10
var y : Int? = 5

print(x,y)
//10 Optional(5)

옵셔널 타입 변수를 선언하기 위해서는 타입 선언부 뒤에 “?” 문자를 쓴다

var index: Int?

- index 변수는 정수 값을 갖거나 아무 값도 갖지 않을 수 있다(nil)

'iOS' 카테고리의 다른 글

iOS (?)  (0) 2023.11.14
iOS (10)  (0) 2023.11.07
iOS (5)  (1) 2023.10.17
iOS (3)  (1) 2023.09.26
iOS (2)  (0) 2023.09.19

+ Recent posts