C#에서 옵셔널 체이닝 (ex A.?B)

 

옵셔널 체이닝 연산자(?.)는 C# 6.0 버전부터 도입된 문법이고,

이를 통해 null인 변수에 대한 속성이나 메서드 호출을 편리하게 처리할 수 있슴 이를 통해 null 체크를 간단하게 처리하면서 코드를 더 간결하게 만들 수 있슴

예를 들어, 객체가 null이 아닌 경우에만 메서드를 호출하고 그렇지 않으면 null을 반환하는 경우, 옵셔널 체이닝을 사용하면 다음과 같이 코드를 작성할 수 있슴

someObject?.SomeMethod();

 

만약 someObject가 null이라면 SomeMethod는 호출되지 않고, null이 아니라면 정상적으로 호출

 

유니티에서는 주로 GameObject나 Component 등이 null인지 확인하고 접근하는 경우에 옵셔널 체이닝을 활용 가능

 
Rect transform Utility 스크립팅
FlipLayoutAxes RectTransform의 크기와 정렬을 수평 및 수직 축을 기준으로 뒤집는다. 옵션으로 자식 요소들도 함께 뒤집을 수 있다.
FlipLayoutOnAxis RectTransform의 정렬을 수평 또는 수직 축을 기준으로 뒤집는다. 옵션으로 자식 요소들도 함께 뒤집을 수 있다.
PixelAdjustPoint 주어진 스크린 좌표를 픽셀 정확한 좌표로 변환한다.
PixelAdjustRect 주어진 RectTransform에 대한 픽셀 정확한 모서리 좌표를 반환한다.
RectangleContainsScreenPoint RectTransform이 주어진 카메라에서 본 스크린 좌표를 포함하는지 여부를 반환한다.
ScreenPointToLocalPointInRectangle 스크린 좌표를 RectTransform의 로컬 좌표로 변환한다.
ScreenPointToWorldPointInRectangle 스크린 좌표를 주어진 RectTransform의 평면 상의 월드 좌표로 변환한다.

 

일반 오브젝트는 Transform 사용

 

UI 오브젝트는 Rect Transform 을 사용함

 

 

UI에 관한 자세한 내용은 아래 블로그 작성자분이 자세하게 정리해놓으셨습니다

https://wergia.tistory.com/184

 

[Unity3D] UI 비법서 (4) - UI 개발자라면 제발 Rect Transform 애용합시다!

UI 비법서 (4) - UI 개발자라면 제발 Rect Transform 애용합시다! 작성 기준 버전 :: 2019.1-2019.2 [이 포스트의 내용은 유튜브 영상으로도 시청하실 수 있습니다] 유니티 개발을 처음으로 공부하는 개발자

wergia.tistory.com

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

Bounds

"Bounds는 좌표축과 정렬된 바운딩 박스를 나타냅니다. 이는 단순히 좌표축에 정렬된 상자로, 어떤 객체를 완전히 둘러싸고 있습니다. 이 상자는 좌표축과의 회전이 없기 때문에 중심점과 크기만으로 정의할 수 있거나, 최소 및 최대 지점으로도 정의할 수 있습니다.

Bounds는 Collider.bounds, Mesh.bounds, 그리고 Renderer.bounds에서 사용됩니다."

변수

center 바운딩 박스의 중심점입니다.
extents 상자의 크기의 절반으로 항상 일정한 값입니다.
max 상자의 최대 지점으로 항상 center + extents와 같습니다.
min 상자의 최소 지점으로 항상 center - extents와 같습니다.
size 상자의 전체 크기로 항상 extents의 두 배입니다.
 

Public 함수

ClosestPoint 바운딩 박스에서 가장 가까운 점을 반환합니다.
Contains 주어진 점이 바운딩 박스 안에 있는지 여부를 확인합니다.
Encapsulate 바운드를 지정된 점을 포함하도록 확장합니다.
Expand 각 면을 따라 크기를 증가시켜 바운드를 확장합니다.
IntersectRay 레이가 이 바운딩 박스와 교차하는지 여부를 확인합니다.
Intersects 다른 바운딩 박스가 이 바운딩 박스와 교차하는지 여부를 확인합니다.
SetMinMax 바운드를 상자의 최소 및 최대 값으로 설정합니다.
SqrDistance 점과 이 바운딩 박스 간의 가장 작은 제곱 거리를 계산합니다.
ToString 바운드에 대한 서식이 잘된 문자열을 반환합니다.

'Unity' 카테고리의 다른 글

[Unity] SerializeField ? 직렬화 ?  (0) 2024.01.22
[Unity C#] Vector3  (0) 2024.01.22
2024-01-10  (0) 2024.01.10
2024_01_08  (0) 2024.01.08
Unity2D) 기본캐릭터 이동조작  (0) 2022.09.05
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

+ Recent posts