새벽의 기록

[SOPT] 문법 스터디 #8 에러처리와 확장 본문

SOPT/문법 스터디

[SOPT] 문법 스터디 #8 에러처리와 확장

OneTen 2024. 11. 18. 01:01
에러 처리
    - do-catch 구문을 사용해봅시다 !
    - throws 에 대해 알아보고, 사용해봅시다.
    - Result Type을 통한 에러 처리에 대해 알아봅시다.
확장
    - 프로토콜 익스텐션(Protocol Extensions)에 대해 알아보고, 이를 사용한 코드를 작성해봅시다.
    - 이 외에도, 확장을 이용한 많은 방법을 통해 코드를 가독성 있게 작성할 수 있습니다. 
	  확장으로 빼면서 가독성이 좋아지는 간단한 코드를 작성하고, 설명해주세요.

 

에러 처리

1. do-catch 구문을 사용해봅시다 !

에러가 발생할 수 있는 코드를 실행하고, 에러가 발생하면 처리할 수 있는 구조.
에러를 던질 수 있는 함수는 throws 키워드를 사용하여 정의한다. do 블록 내에서 에러가 발생하면 catch 블록으로 넘어간다.

import Foundation

func readFileContent(fileName: String) throws -> String {
    let fileURL = URL(fileURLWithPath: fileName)
    return try String(contentsOf: fileURL, encoding: .utf8)
}

do {
    let content = try readFileContent(fileName: "sample.txt")
    print("File content: \\(content)")
} catch {
    print("Failed to read file: \\(error.localizedDescription)")
}

 

2. throws 에 대해 알아보고, 사용해봅시다.

에러가 발생할 수 있는 함수나 메서드를 정의할 때 사용.
throws 키워드는 에러가 발생할 가능성이 있음을 명시하며, 해당 함수를 호출할 때 try 키워드를 함께 사용해야한다.

import Foundation

enum DivisionError: Error {
    case divisionByZero
}

func divide(_ numerator: Double, by denominator: Double) throws -> Double {
    guard denominator != 0 else {
        throw DivisionError.divisionByZero
    }
    return numerator / denominator
}

do {
    let result = try divide(10, by: 0)
    print("Result: \\(result)")
} catch DivisionError.divisionByZero {
    print("Cannot divide by zero.")
} catch {
    print("An unexpected error occurred: \\(error)")
}

 

3. Result Type을 통한 에러 처리에 대해 알아봅시다.

비동기 코드에서 주로 사용되며, 성공 또는 실패 결과를 리턴할 때 유용하다.
→ 이번 4주차 과제 API 연결 부분에서 사용됨
 
Result 타입은 success와 failure 두 가지 케이스로 이루어져 있어, 성공할 경우 원하는 값을 리턴하고 실패할 경우 에러를 리턴할 수 있다.

    // 회원가입
    func signUp(username: String, password: String, hobby: String, completion: @escaping (Result<Bool, NetworkError>) -> Void){

        // baseURL + /user = <http://211.188.53.75:8080/user>
        let url = Environment.baseURL + "/user"

        let parameters = SignUpRequest(username: username, password: password, hobby: hobby)

        AF.request(url, method: .post, parameters: parameters, encoder: JSONParameterEncoder.default)
            .validate()
            .response { [weak self] response in

                guard let statusCode = response.response?.statusCode,
                      let data = response.data,
                      let self
                else {
                    completion(.failure(.unknownError))
                    return
                }

                switch response.result {
                case .success:
                    completion(.success(true))
                case .failure:
                    let error = self.handleStatusCode(statusCode, data: data)
                    completion(.failure(error))
                }
            }
    }

 

확장

1. 프로토콜 익스텐션(Protocol Extensions)에 대해 알아보고, 이를 사용한 코드를 작성해봅시다.

프로토콜 익스텐션은 프로토콜에 기본 구현을 제공하여, 채택한 타입이 직접 구현하지 않아도 프로토콜이 요구하는 기능을 사용할 수 있게 하는 기능.
프로토콜을 채택하는 모든 타입에 동일한 메서드, 프로퍼티, 연산 등을 제공할 수 있다.

protocol Describable {
    var description: String { get }
    func describe()
}

extension Describable {
    var description: String {
        return "This is a describable object."
    }
    
    func describe() {
        print(description)
    }
}

struct Car: Describable {
    var make: String
    var model: String
    
    var description: String {
        return "Car: \\(make) \\(model)"
    }
}

struct Animal: Describable {
    var species: String
    
    // 기본 구현인 "This is a describable object." 사용
}

let car = Car(make: "Tesla", model: "Model S")
let animal = Animal(species: "Dog")

car.describe()   // 출력: "Car: Tesla Model S"
animal.describe() // 출력: "This is a describable object."

 

2. 이 외에도, 확장을 이용한 많은 방법을 통해 코드를 가독성 있게 작성할 수 있습니다. 확장으로 빼면서 가독성이 좋아지는 간단한 코드를 작성하고, 설명해주세요.

 
4주차 과제를 하며 UiTextfield를 사용할 일이 많았는데, 대문자 시작하는 거 막아주고, 자꾸 자동 수정 뜨고, 수정하려고 하면 텍스트 초기화되고 그래서 일일이 autocapitalizationType, autocorrectionType, clearsOnBeginEditing 이런 거 넣어주다 보니까 귀찮기도 하고 너무 길어지기도 해서 익스텐션으로 빼줬다.

extension UITextField {
    
    func configureDefaultSettings() {
        self.autocorrectionType = .no           // 자동 수정 비활성화
        self.spellCheckingType = .no            // 맞춤법 검사 비활성화
        self.autocapitalizationType = .none     // 자동 대문자 비활성화
        self.clearButtonMode = .always          // 입력내용 한번에 지우는 x버튼(오른쪽)
        self.clearsOnBeginEditing = false       // 편집 시 기존 텍스트필드값 초기화 안되게끔
    }
    
    // 왼쪽 패딩
    func addLeftPadding() {
        let paddingView = UIView(frame: CGRect(x: 0, y: 0, width: 10, height: self.frame.height))
        self.leftView = paddingView
        self.leftViewMode = ViewMode.always
    }
    
}

 
 
기존 작성 코드

userIdTextField.do {
            $0.placeholder = "ID"
            $0.font = .systemFont(ofSize: 32)
            $0.borderStyle = .bezel
            $0.autocorrectionType = .no           
		        $0.spellCheckingType = .no            
		        $0.autocapitalizationType = .none     
		        $0.clearButtonMode = .always          
		        $0.clearsOnBeginEditing = false
		        $0.leftView = UIView(frame: CGRect(x: 0, y: 0, width: 10, height: self.frame.height))
		        $0.leftViewMode = ViewMode.always  
        }

 
 
익스텐션을 사용한 코드

userIdTextField.do {
            $0.placeholder = "ID"
            $0.font = .systemFont(ofSize: 32)
            $0.borderStyle = .bezel
            $0.configureDefaultSettings()
            $0.addLeftPadding()
        }
Comments