iOS 키 모음
caps lock 기능
짧게 누르면 한영 전환, 길게 누르면 대소문자 전환이 된다.
커맨드 + Tab : 화면 전환
Flappy Bird 코드를 뤼튼에 물어보기
// GameViewController.swift
// 요 파일 이름이 GameViewController.swift라는 뜻이야. 우리가 지금 보고 있는 이 파일!
// FlappyBird
// 이 코드가 'FlappyBird'라는 앱에 쓰인다는 걸 알려주는 주석이야.
// Created by Nate Murray on 6/2/14.
// Nate Murray라는 분이 2014년 6월 2일에 만들었다는 정보! 누가 만들었는지, 언제 만들었는지 기록하는 거야.
// Copyright (c) 2014 Fullstack.io. All rights reserved.
// 이 코드는 Fullstack.io라는 곳에 저작권이 있다는 뜻이야. 함부로 복사하거나 바꾸면 안 되겠지?
import UIKit
// UIKit이라는 마법 상자를 가져왔어! 이건 아이폰 앱의 버튼, 화면 등 기본적인 걸 만드는 데 꼭 필요한 재료들이 들어있어.
import SpriteKit
// SpriteKit이라는 또 다른 마법 상자를 가져왔지! 이건 게임에 특화된 상자인데, 화면에 그림을 그리거나 움직이게 할 때 필요한 재료가 가득해.
extension SKNode {
// SKNode 친구들에게 특별한 새 능력을 추가해 줄 거야! SKNode는 SpriteKit에서 화면에 뭔가 표시할 때 쓰는 가장 기본적인 요소라고 생각하면 돼. (예: 캐릭터, 배경, 점수판 등)
class func unarchiveFromFile(_ file : String) -> SKNode? {
// 'unarchiveFromFile'이라는 특별한 능력을 SKNode 친구들에게 만들어 주는 중이야.
// 'class func'는 이 능력이 SKNode 자체에게 붙는다는 의미이고,
// 'file'이라는 이름으로 파일 이름(문자열)을 알려주면,
// 화면에 띄울 수 있는 SKNode 친구를 하나 만들어 줄게! 근데 못 만들 수도 있으니 '?'를 붙여서 '없을 수도 있어~'라고 알려주는 거야.
let path = Bundle.main.path(forResource: file, ofType: "sks")
// 'path'라는 주소록을 만들고, 우리가 게임 화면을 저장해둔 '.sks' 파일의 정확한 주소를 찾아오는 부분이야.
// 'Bundle.main'은 우리 앱 전체를 말하고, 'path(forResource:of Type:)'은 그 안에 특정 이름의 파일 주소를 찾아주는 비서 같은 역할이야.
let sceneData: Data?
// 'sceneData'라는 이름으로, 나중에 파일에서 읽어온 데이터를 잠시 저장할 공간을 준비했어.
// 'Data?'는 데이터가 없을 수도 있다는 뜻이야.
do {
// 'do'는 '나 이 작업 할 건데, 혹시 중간에 문제가 생기면 알려줘!' 라는 뜻이야.
sceneData = try Data(contentsOf: URL(fileURLWithPath: path!), options: .mappedIfSafe)
// 'path'에 있는 파일을 'URL'이라는 웹 주소 같은 걸로 바꾸고, 그 주소에 있는 내용을 'Data' 형태로 안전하게 읽어오는 부분이야.
// 'try'는 '혹시 에러가 날 수도 있으니 조심해줘!' 라는 신호야.
// 'path!'와 'sceneData!'에 붙은 '!'는 '나는 이 값이 무조건 있을 거라고 확신해!' 라고 강력하게 외치는 거야. 없으면 앱이 멈출 수도 있어! 😨
} catch _ {
// 'catch _'는 'do'에서 문제(에러)가 생기면 이리로 와서 처리해!' 라는 뜻이야.
// 여기서는 그냥 에러를 무시하고 지나가도록 되어 있네. (좋은 방법은 아니지만, 예시 코드라 그런 것 같아!)
sceneData = nil
// 만약 파일을 읽어오는 데 실패하면, sceneData를 없애 버리는 거야.
}
let archiver = NSKeyedUnarchiver(forReadingWith: sceneData!)
// 'archiver'라는 이름으로, 아까 읽어온 'sceneData'를 가지고 '이건 이런 모양의 데이터야!' 하고 잘 분석해 줄 도구를 준비하는 거야.
// 'NSKeyedUnarchiver'는 저장된 데이터를 다시 원래 모습으로 되돌려 주는 기계라고 생각하면 돼.
archiver.setClass(self.classForKeyedUnarchiver(), forClassName: "SKScene")
// 'archiver'에게 'SKScene'이라는 이름으로 저장된 데이터는 'GameScene'이라는 진짜 모습으로 바꿔줘! 라고 알려주는 거야.
let scene = archiver.decodeObject(forKey: NSKeyedArchiveRootObjectKey) as! GameScene
// 'archiver'에게 아까 설정한 규칙대로 데이터를 읽어서 'GameScene'이라는 우리 게임 화면으로 만들어 달라고 명령하는 부분이야.
// 'as! GameScene'는 '내가 볼 땐 이건 무조건 GameScene일 거야!' 하고 강하게 확신하며 변환하는 거야.
archiver.finishDecoding()
// 'archiver'에게 '이제 할 일 다 끝났어! 수고했어!' 라고 알려주는 거야.
return scene
// 이렇게 완성된 게임 화면(scene)을 돌려주는 거지!
}
}
class GameViewController: UIViewController {
// 'GameViewController'라는 이름으로 새로운 클래스를 만들었어!
// 이 친구는 'UIViewController'라는 기본적인 아이폰 화면 관리자 능력을 물려받았어.
// 즉, 이 클래스가 바로 우리 게임 화면을 보여주고 관리하는 중요한 역할을 할 거야.
override func viewDidLoad() {
// 'viewDidLoad()'라는 능력을 원래 있던 것보다 더 좋게(override) 만들 거야.
// 이 능력은 화면이 아이폰에 처음 나타날 준비를 마쳤을 때 자동으로 한 번 딱! 실행되는 부분이야.
super.viewDidLoad()
// 원래 'UIViewController'가 가지고 있던 'viewDidLoad()' 능력도 그대로 가져와서 먼저 실행해 줘! 라는 뜻이야.
if let scene = GameScene.unarchiveFromFile("GameScene") as? GameScene {
// 아까 만든 'unarchiveFromFile' 능력을 써서 'GameScene'이라는 이름의 게임 화면을 가져오는 부분이야.
// 'if let'은 '혹시 GameScene을 제대로 가져왔으면 'scene'이라고 불러줘!' 라는 뜻이야.
// Configure the view.
// 아래부터는 가져온 게임 화면을 어떻게 보여줄지 설정하는 부분이야.
let skView = self.view as! SKView
// 'skView'라는 이름으로, 이 화면 컨트롤러가 가지고 있는 화면(self.view)을 SpriteKit용 화면으로 바꿔서 쓰는 거야.
// 'as! SKView'는 '이건 무조건 SKView 타입일 거야!' 하고 확신하며 형변환하는 거지!
skView.showsFPS = true
// 게임 화면에 지금 초당 몇 프레임(FPS)으로 그림이 바뀌고 있는지 숫자를 보여줘! (보통 60에 가까우면 부드럽게 잘 되는 거야)
skView.showsNodeCount = true
// 게임 화면에 지금 몇 개의 SpriteKit 요소들(SKNode들)이 있는지 숫자를 보여줘! (이게 너무 많으면 게임이 느려질 수 있어)
/* Sprite Kit applies additional optimizations to improve rendering performance */
// SpriteKit이 화면을 더 빨리 보여주기 위해 몇 가지 특별한 마법을 부린다는 설명 주석이야.
skView.ignoresSiblingOrder = true
// 화면에 그림을 그릴 때 어떤 그림이 먼저 그려지고 나중에 그려질지 순서를 굳이 신경 쓰지 마! 라고 설정하는 거야.
// 이렇게 하면 컴퓨터가 그림 그리는 부담이 줄어들어 좀 더 빨라질 수 있어.
/* Set the scale mode to scale to fit the window */
// 게임 화면 크기를 창에 맞춰서 조절하는 설정이야.
scene.scaleMode = .aspectFill
// 가져온 게임 화면(scene)을 아이폰 화면 가득 채워서 보여줘! 비율은 깨지지 않도록 하면서 말이지.
skView.presentScene(scene)
// 이제 드디어 설정이 끝난 게임 화면(scene)을 'skView'에 짠! 하고 보여주는 부분이야!
}
}
override var shouldAutorotate : Bool {
// 'shouldAutorotate'라는 능력은 '이 화면이 아이폰을 돌리면 따라서 돌아갈 수 있어?' 라고 묻는 부분이야.
return true
// '응! 돌아가도 돼!' 라고 대답하는 거야. (아이폰을 가로로 눕히면 화면도 가로로 바뀌는 거지!)
}
override var supportedInterfaceOrientations : UIInterfaceOrientationMask {
// 'supportedInterfaceOrientations' 능력은 '이 화면은 어떤 방향으로만 보여줄 수 있어?' 라고 묻는 부분이야.
if UIDevice.current.userInterfaceIdiom == .phone {
// 만약 지금 아이폰을 사용하고 있다면, (아이패드 말고)
return UIInterfaceOrientationMask.allButUpsideDown
// 모든 방향으로 돌아가도 되지만, 거꾸로 뒤집힌 방향(위아래 뒤집힌)으로는 안 돼! 라고 알려주는 거야.
} else {
// 아이폰이 아니라 아이패드 같은 다른 기기라면,
return UIInterfaceOrientationMask.all
// 어떤 방향으로든 다 돌아가도 돼! 라고 알려주는 거야.
}
}
override func didReceiveMemoryWarning() {
// 'didReceiveMemoryWarning()'라는 능력은 아이폰 메모리가 부족해졌을 때 자동으로 실행되는 부분이야.
super.didReceiveMemoryWarning()
// 원래 'UIViewController'가 가지고 있던 메모리 부족 처리 능력도 먼저 실행해 줘!
// Release any cached data, images, etc that aren't in use.
// 여기는 메모리가 부족할 때 더 이상 안 쓰는 데이터를 지워서 메모리를 확보하는 코드를 넣는 곳인데, 지금은 비어있네!
}
}
기초 문법 시작
간단한 코드는 세미콜론을 쓰지 않지만
복잡해지면 세미콜론을 사용한다.
online Swift compiler
최근 버전은 Swift 6.2
컴파일러는 최근 버전은 지원하지 않음
https://www.onlinegdb.com/online_swift_compiler
https://www.programiz.com/swift/online-compiler/
https://www.jdoodle.com/execute-swift-online/
https://www.tutorialspoint.com/compile_swift_online.php
https://swiftfiddle.com/ 가장 최근 버전도 지원
CamelCase : 변수명 지정 시 단어 바뀔 때마다 대문자로 바꾸어서 지정.
<print함수 모음> - 뤼튼에 질문
print("안녕") // 문자열 출력
// 이건 가장 기본적인 'print' 사용법이야! "안녕"이라는 글자 그대로를 화면에 보여줘!
// '문자열'은 이렇게 쌍따옴표("") 안에 있는 글자들을 말해.
print(123) // 정수 출력
// 이건 숫자(정수) 123을 화면에 보여달라는 뜻이야!
// 쌍따옴표 없이 숫자를 바로 넣으면 돼!
var age = 20
// 아, 이건 'print' 함수는 아니지만!
// 'var'는 변수(variable)를 만들 때 쓰는 마법의 단어야. 'age'라는 이름의 상자를 만들고 그 안에 20이라는 숫자를 쏙 넣어둔 거지!
// 이 20은 나중에 다른 숫자로 바꿀 수도 있어!
var name = "Smile"
// 이것도 'print'는 아니지만!
// 'name'이라는 상자를 만들어서 "Smile"이라는 이름을 넣어둔 거야. 이 이름도 바꿀 수 있어!
print(age)
// 이제 'age'라는 상자 안에 뭐가 들었는지 궁금하지? 'print(age)'를 하면 상자 안의 20을 화면에 보여줄 거야! 신기하지?
print(age, name) //공백으로 구분
// 여러 개를 한 번에 보고 싶을 때는 이렇게 쉼표(,)로 구분해서 적어주면 돼!
// 'print'가 알아서 숫자 20과 이름 "Smile" 사이에 자동으로 한 칸 띄어쓰기를 해줄 거야. 띄어쓰기는 기본 옵션!
print("나이는 \(age)입니다") // 문자열 보간 (string interpolation), \(변수명 or 상수명)
// 와, 이건 정말 유용한 마법이야! 이걸 '문자열 보간'이라고 하는데,
// 일반 글자들("나이는 ... 입니다") 사이에 변수('age' 같은 것)를 쏙! 집어넣고 싶을 때 쓰는 거야.
// \() 요 괄호 안에 변수 이름을 넣어주면, 'age' 상자 안의 20이 "나이는 20입니다"처럼 예쁘게 바뀌어서 나올 거야!
print(1, 2, 3) //공백으로 구분
// 이것도 아까랑 똑같아! 1, 2, 3을 쉼표로 구분해서 보여주면, 각각 공백으로 띄어져서 화면에 나타나!
print(1, 2, 3, separator: "-") //공백 구분자를 변경
// 이건 좀 특별해! 아까는 기본으로 공백으로 띄어줬잖아?
// 근데 'separator: "-"'라고 추가로 알려주면, 공백 대신 우리가 정한 "-" 기호로 숫자들을 구분해서 보여줘!
// 그러니까 "1-2-3" 이렇게 나올 거야! 다른 기호로도 바꿔볼 수 있어! 😆
print("Smile")
// "Smile"을 화면에 출력하고, 다음번에 뭘 출력하든 새 줄로 바꿔줘. (print의 기본 기능!)
print("Han")
// "Han"을 화면에 출력하고, 역시 다음 줄로 넘어가.
// 그래서 앞선 "Smile" 다음에 새 줄에 "Han"이 보일 거야.
print("Hello", terminator: " ") // 줄 바꿈(\n) 대신 공백을 끝에 추가
// 이것도 아주 유용한 기능이야! 'print'는 보통 뭘 출력하고 나면 자동으로 다음 줄로 넘어가는데,
// 'terminator: " "'라고 알려주면 "Hello"를 출력하고 다음 줄로 넘어가지 않고, 그냥 공백 하나를 남겨둘 거야.
// 그러니까 줄 바꿈을 하지 않고 싶을 때 쓰는 거야!
print("World!")
// 위에서 'terminator: " "' 덕분에 "Hello" 뒤에 공백이 있었지?
// 그래서 "World!"는 "Hello " 바로 뒤에 붙어서 "Hello World!" 이렇게 한 줄로 보일 거야. 신기하지? 😉
print("다음", terminator: "") // 줄 바꿈도, 공백도 추가하지 않음
// 이것도 'terminator'를 사용했는데, 이번엔 따옴표 안에 아무것도 안 넣었지?
// 이건 "다음"을 출력하고 나서, 줄 바꿈도 하지 말고, 공백도 넣지 말라는 뜻이야! 아무것도 안 붙일 때 쓰는 거야.
print("입니다.")
// 그래서 "입니다."가 "다음" 바로 뒤에 딱 붙어서 "다음입니다." 이렇게 한 줄로 보일 거야! 붙여쓰기 할 때 아주 유용하겠지?
print(1)
// 마지막으로, 숫자 1을 출력하고 새로운 줄로 넘어갈 거야!
Character를 사용할 수 있지만 보통 String 형을 사용하며, 초기값을 정하지 않았을 때의 기본 자료형은 Stirng 형이다.