iOS Second Class

import UIKit
import SpriteKit

// SKNode의 확장(extension)을 정의
extension SKNode {
    
    // .sks 파일을 언아카이브하여 SKNode 객체로 반환하는 함수
    class func unarchiveFromFile(_ file : String) -> SKNode? {
        
        // .sks 파일 경로를 가져옴
        let path = Bundle.main.path(forResource: file, ofType: "sks")
        
        // 파일을 Data 객체로 변환
        let sceneData: Data?
        do {
            sceneData = try Data(contentsOf: URL(fileURLWithPath: path!), options: .mappedIfSafe)
        } catch _ {
            sceneData = nil
        }
        
        // NSKeyedUnarchiver 객체 생성하여 Data를 언아카이브
        let archiver = NSKeyedUnarchiver(forReadingWith: sceneData!)
        
        // SKScene의 클래스를 할당 (언아카이브 시 사용할 클래스 설정)
        archiver.setClass(self.classForKeyedUnarchiver(), forClassName: "SKScene")
        
        // GameScene 객체를 디코딩하여 가져옴
        let scene = archiver.decodeObject(forKey: NSKeyedArchiveRootObjectKey) as! GameScene
        archiver.finishDecoding() // 디코딩 종료
        
        // 반환된 GameScene 객체를 반환
        return scene
    }
}

// GameViewController 클래스 정의
class GameViewController: UIViewController {

    // 화면이 로드될 때 호출되는 함수
    override func viewDidLoad() {
        super.viewDidLoad()

        // "GameScene"을 unarchiveFromFile로 불러오기
        if let scene = GameScene.unarchiveFromFile("GameScene") as? GameScene {
            
            // skView를 현재 뷰로 설정
            let skView = self.view as! SKView
            
            // FPS(초당 프레임 수)와 노드 수를 표시하도록 설정
            skView.showsFPS = true
            skView.showsNodeCount = true
            
            /* SpriteKit이 렌더링 성능을 향상시키기 위한 추가 최적화 적용 */
            skView.ignoresSiblingOrder = true
            
            /* 화면 크기에 맞게 씬의 스케일 모드를 설정 */
            scene.scaleMode = .aspectFill
            
            // 씬을 skView에 표시
            skView.presentScene(scene)
        }
    }

    // 회전 가능 여부를 반환하는 프로퍼티
    override var shouldAutorotate : Bool {
        return true
    }

    // 지원하는 인터페이스 방향을 반환하는 프로퍼티
    override var supportedInterfaceOrientations : UIInterfaceOrientationMask {
        if UIDevice.current.userInterfaceIdiom == .phone {
            // 아이폰은 세로 방향(업사이드 다운 제외)을 지원
            return UIInterfaceOrientationMask.allButUpsideDown
        } else {
            // 아이패드는 모든 방향을 지원
            return UIInterfaceOrientationMask.all
        }
    }

    // 메모리 경고 시 호출되는 함수
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // 사용하지 않는 캐시 데이터나 이미지 등을 해제
    }
}
Online Swift Compiler - online editor
OnlineGDB is online IDE with swift compiler. Quick and easy way to run swift scripts online.
var x = 10
print(x) // 변수 x의 값인 10을 출력

print("안녕") // 문자열 "안녕"을 출력

print(123) // 정수 123을 출력

var age = 20
var name = "Smile"
print(age) // 변수 age의 값인 20을 출력

print(age, name) // 변수 age와 name을 공백으로 구분하여 출력 (20 Smile)

print("나이는 \(age)입니다") // 문자열 보간을 사용하여 "나이는 20입니다"를 출력

print(1, 2, 3) // 정수 1, 2, 3을 공백으로 구분하여 출력 (1 2 3)

print(1, 2, 3, separator: "-") // separator를 "-"로 설정하여 1-2-3으로 출력

print("Smile") // 문자열 "Smile"을 출력

print("Han") // 문자열 "Han"을 출력

print("Hello", terminator: " ") // "Hello" 출력 후 줄 바꿈 없이 공백을 추가하여 출력

print("World!") // "World!"를 출력

print("다음", terminator: "") // "다음" 출력 후 줄 바꿈이나 공백 없이 출력

print("입니다.") // "입니다."를 출력

var 대신 let을 사용하는 이유는 **불변성(immutability)**을 유지하고, 코드의 안정성, 가독성, 예측 가능성을 향상시키기 위해서입니다. Swift에서는 가급적이면 값이 변경되지 않기를 바라는 변수나 상수는 let으로 선언하는 것이 권장됩니다. 그 이유는 아래와 같습니다.

1. 불변성(Immutable) 보장

  • let을 사용하면 값을 한 번 설정한 후, 해당 값을 변경할 수 없습니다. 불변성은 코드의 예측 가능성을 높이고, 의도치 않은 데이터 변경을 방지하는 데 도움을 줍니다.
  • 예를 들어, 값을 변경할 수 없는 상수를 사용하면 해당 값이 어떤 과정에서든 바뀌지 않음을 보장할 수 있습니다. 이는 특히 버그를 예방하고, 코드의 안정성을 높입니다.
let pi = 3.14159
// pi = 3.14 // 오류 발생: Cannot assign to value: 'pi' is a 'let' constant

2. 의도 표현

  • let을 사용하면 "이 값은 변경되지 않겠다"는 의도를 명확하게 전달할 수 있습니다. 코드를 읽는 다른 사람이나, 자신이 나중에 코드를 보았을 때 let을 사용한 변수는 불변이라는 것을 즉시 알 수 있습니다.
  • 코드가 간결해지고, 그 목적이 더 분명해집니다. 예를 들어, let을 사용하면 이 변수는 "상수로서의 역할"을 한다고 명확히 알 수 있습니다.
let maxLoginAttempts = 3  // 로그인 시도 횟수는 변경되지 않음을 명확히 표현

3. 컴파일러 최적화와 성능 향상

  • 불변성은 컴파일러가 최적화 작업을 할 때 유리하게 작용할 수 있습니다. 불변 값에 대해서는 메모리 캐싱이나 성능 최적화가 더 용이합니다.
  • 예를 들어, let으로 선언된 값은 변경되지 않기 때문에, 이를 참조하는 다른 코드에서 그 값을 읽을 때 더 효율적인 처리가 가능합니다.
let maxUsers = 100  // 이 값은 변경되지 않기 때문에 캐시될 수 있음

4. 스레드 안전성 (Thread Safety)

  • 멀티스레드 환경에서 let으로 선언된 값은 변경되지 않기 때문에 동기화 문제를 피할 수 있습니다.
  • 반면, var로 선언된 값은 여러 스레드에서 변경될 수 있으므로, 값이 동시에 변경되는 경우 **경쟁 상태(race condition)**가 발생할 수 있습니다. let을 사용하면 이러한 문제를 자연스럽게 방지할 수 있습니다.
let sharedResource = SomeClass()  // 스레드에서 안전하게 읽을 수 있음

5. 코드 가독성 및 유지보수성 향상

  • 값이 변경되지 않음을 보장하기 때문에, 코드를 읽는 사람이 그 변수의 값이 절대로 변경되지 않는 것을 바로 알 수 있습니다. 이는 코드 이해를 더 쉽게 만듭니다.
  • 또한, 불변 값을 사용하면 해당 값이 실수로 변경되는 상황을 예방할 수 있으며, 코드의 버그 발생 가능성을 줄입니다.
let userName = "Alice"  // 이 값은 변경되지 않음, 함수에서 이름을 읽기만 함

6. 함수 및 메서드의 인자 전달

  • 함수나 메서드의 매개변수를 let으로 선언하면, 해당 인자의 값은 변경되지 않음을 보장할 수 있습니다. 이는 함수형 프로그래밍 스타일을 선호할 때 유용합니다.
func printUserInfo(name: String, age: Int) {
    let greeting = "Hello, \(name)"
    // name과 age는 함수 내부에서 변경되지 않음
    print(greeting, "You are \(age) years old.")
}

7. 변수의 상태 변경을 피하기 위한 목적

  • 불필요하게 변수를 변경하는 것을 피하는 것이 좋습니다. var로 선언된 변수는 언제든지 값을 변경할 수 있으므로, 그 값이 변경되지 않기를 원하는 경우 let을 사용하는 것이 더 안전합니다.
  • 상태의 변화를 추적해야 할 필요가 없다면, let을 사용하여 코드의 예측 가능성을 높일 수 있습니다.

8. Swift의 코딩 관습과 Best Practices

  • Swift에서 let기본적으로 사용하고, 값이 변경되는 경우에만 var를 사용하는 것이 권장되는 관습입니다. 이는 코드의 안정성가독성을 높이는 데 도움을 줍니다.
let maxScore = 100  // 고정된 상수값
var currentScore = 0  // 현재 점수는 변화할 수 있음

9. 상수와 변수의 혼합 사용

  • 경우에 따라, 특정 값이 불변임을 보장할 때 let을 사용하고, 값이 변할 필요가 있는 경우 var를 사용하는 것이 더 명확하고 직관적입니다.
  • 예를 들어, 상수값과 변수값을 함께 사용하면 두 가지의 차이를 쉽게 구분할 수 있습니다.
let maxAttempts = 5  // 시도 횟수는 변경되지 않음
var currentAttempts = 0  // 현재 시도 횟수는 변할 수 있음

결론

let을 사용하여 값을 불변으로 유지함으로써, 코드의 안정성, 가독성, 성능을 개선할 수 있습니다. 가능한 한 값을 변경할 필요가 없는 경우에는 let을 사용하고, 실제로 값을 변경해야 할 경우에만 var를 사용하는 것이 Swift의 권장 스타일입니다. 이를 통해 코드가 더 안전하고 예측 가능하며, 유지보수하기 쉬운 형태로 발전할 수 있습니다.