Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

defer란 무엇인지 설명하시오 #36

Open
Hminchae opened this issue May 9, 2024 · 1 comment
Open

defer란 무엇인지 설명하시오 #36

Hminchae opened this issue May 9, 2024 · 1 comment
Assignees

Comments

@Hminchae
Copy link
Member

Hminchae commented May 9, 2024

No description provided.

@Hminchae Hminchae self-assigned this May 9, 2024
@Hminchae Hminchae changed the title KVO 동작 방식에 대해 설명하시오 KVO 및 KVC에 대하여 설명하시오 May 9, 2024
@Hminchae Hminchae changed the title KVO 및 KVC에 대하여 설명하시오 defer란 무엇인지 설명하시오 May 9, 2024
@4T2F 4T2F deleted a comment from Phangg May 9, 2024
@4T2F 4T2F deleted a comment from hamfan524 May 9, 2024
@Hminchae
Copy link
Member Author

Hminchae commented May 9, 2024

defer Statement

  • defer Statement 는 함수 안에 작성 되는 non-escaping closure이며 함수 작성된 위치와 상관없이 함수가 종료되기 직전에 실행 되는 구문
  • defer 구문은 후 처리 방식을 할 때 사용되며 함수 scpoe 범위 내에서 가장 마지막에 실행이 된다.
  • defer 구문을 중첩으로 사용 할 수 있으며 LIFO 형식으로 가장 마지막에 있는 defer 가 먼저 실행되고 가장 처음에 있는 defer 가 마지막에 실행됨
  • defer 구문 내부에는 break, return, throw 등과 같이 구문을 빠져나갈 수 있는 코드 또는 오류를 던지는 코드를 작성하면 오류가 발생됨
func sayNumber() {
    defer {
        print("print check : 1")
    }
    print("print check : 2")
}

// print check : 2
// print check : 1

func sayCheckNumber() {
    defer {
        for i in 0..<5 {
            print("for loop check : \(i)")
        }
    }
    print("print check : 5")
}

// print check : 5
// for loop check : 0
// for loop check : 1
// for loop check : 2
// for loop check : 3
// for loop check : 4


func sayNestedNumber() {
    defer {
        print("print check : 1")
    }
    
    defer {
        print("print check : 2")
    }
    
    defer {
        print("print check : 3")
    }
    print("print check : 4")
}


// print check : 4
// print check : 3
// print check : 2
// print check : 1

defer가 호출되는 순서

  • 함수 내에 한 개 있을 때
    • 함수의 가장 마지막에 실행된다.
func test() {
    print("First print")
    
    defer { print("!!defer!!")}
    
    print("Second print")
}
test()

/* 결과
First print
Second print
!!defer!
*/
  • 함수 내에 defer가 여러 개 있을 때
    • 끝에 있는 defer 부터 실행된다(LIFO)
func test2() {
    defer { print("1st defer - first") }
    defer { print("2nd defer") }
    defer { print("3rd defer - last") }
}
test2()

/* 결과
3rd defer - last
2nd defer
1st defer - first
*/
  • defer가 중첩되어 있을 때
    • 가장 바깥 쪽에 있는 defer가 가장 먼저 실행된다.
func test3() {
    defer {
        defer {
            defer {
                print("1st defer - inner")
            }
            print("2nd defer")
        }
        print("3rd defer - outer")
    }
}
test3()

/* 결과
3rd defer - outer
2nd defer
1st defer - inner
*/

defer가 호출되지 않는 경우

  • defer 를 읽기 전에 함수가 종료될 때
func test4() {
    print("1st print")
    return
    
    defer { print("defer~~") }
    
    print("2nd print")
}
test4()

/* 결과
1st print
*/
  • throw를 이용해서 오류를 던질 경우
func example() throws -> Int {
    defer { print("1") }
    
    enum ExampleError {
        case error
    }
    
    throw ExampleError.error
    defer { print("2") }
    
    print("3")
}

example()

/*
Print

1
*/
  • guard문을 사용하여 중간에 함수를 종료하는 경우
func example() {
    defer { print("1") } 
    guard false else { return }
    
    defer { print("2") }
}

example()

/*
Print

1
*/
  • 함수의 리턴값이 Never(비반환함수)인 경우

defer를 사용하는 경우

  • 함수가 종료하기 직전에 정리해야할 변수나, 상수를 처리해야할 용도로 사용한다.
  • deferNSLock 클래스를 통해 멀티 스레딩 환경에서 Thread-Safe 하게 작업을 할 수 있도록 도와주며 deadlock 을 방지 할 수 있기 때문에 함수 종료 직전에 DB 등을 닫아주는 용도로 사용하면 보장을 받을 수 있다.
class MyResource {
    private var data: Int = 0
    private let lock = NSLock()

    func updateData() {
        lock.lock()  // 데이터를 잠금

        defer {
            lock.unlock()  // 함수가 끝나기 전에 반드시 데이터 잠금을 해제
        }

        // 데이터를 안전하게 업데이트
        data += 1
        print("Data updated to \(data)")
    }
}

let resource = MyResource()

// 병렬로 데이터를 업데이트하는 스레드를 실행
DispatchQueue.global().async {
    resource.updateData()
}
DispatchQueue.global().async {
    resource.updateData()
}
  • 에러를 처리하는 catching 과정에서 특수한 로직을 처리하고 제어권을 반환하기 위하여 defer 구문을 사용할 수 있다. 예로들어 아래와 같이 인터넷 연결이 끊어졌을 때 불완전한 파일을 삭제하는 로직을 구현할 수 있음
func handleFileTransfer() {
    
    defer {
        print("임시파일을 제거합니다.")
    }
    
    do {
        try simulateFileTransfer(connectionExists: true)
        print("File transfer successful")
    } catch let error as FileTransferError {
        switch error {
        case .fileNotFound:
            print("File not found: \(error.localizedDescription)")
        case .fileCorrupted:
            print("File corrupted: \(error.localizedDescription)")
        }
    } catch {
        print("An unexpected error occurred: \(error.localizedDescription)")
    }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant