issue navigator이 떴을때 iOS에서 UI 요소의 위치와 크기를 동적으로 조정하기 위한 시스템 인 오토 레이아웃(Autolayout)이 필요
//
// ViewController.swift
// BMI_kdh
//
// Created by 소프트웨어컴퓨터 on 2024/11/13.
//
import UIKit
class ViewController: UIViewController {
@IBOutlet weak var txtHeight: UITextField!
@IBOutlet weak var txtWeight: UITextField!
@IBOutlet weak var lblResult: UILabel!
@IBAction func calcBmi(_ sender: UIButton) {
let weight = 60.0
let height = 170.0
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 = "저체중"
}
print("BMI:\(shortenedBmi), 판정:\(body)")
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
}
버튼을 누를때 앱에서는 안보이고 debug area에 보임
//
// ViewController.swift
// BMI_kdh
//
// Created by 소프트웨어컴퓨터 on 2024/11/13.
//
import UIKit
class ViewController: UIViewController {
@IBOutlet weak var txtHeight: UITextField!
@IBOutlet weak var txtWeight: UITextField!
@IBOutlet weak var lblResult: UILabel!
@IBAction func calcBmi(_ sender: UIButton) {
let weight = Double(txtWeight.text!)!//txtWeight.text은 옵셔널 string임 강제 언래핑!해야됨, double도 강제 언래핑! /text필드에 둘 다 값을 넣지 않으면 crash가 남
let height = Double(txtHeight.text!)!
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 = "저체중"
}
print("BMI:\(shortenedBmi), 판정:\(body)")
lblResult.text = "BMI:\(shortenedBmi), 판정: \(body)"
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
}
let height = Double(txtHeight.text!)!
let weight = Double(txtWeight.text!)!
첫 번째 !: txtHeight.text와 txtWeight.text는 옵셔널(Optional) 타입입니다. 즉, 이 값이 nil일 수도 있음을 나타냅니다. !를 사용하여 이 옵셔널 값을 강제로 언래핑하여 실제 문자열 값을 가져옵니다. 만약 이 값이 nil이라면 런타임 오류가 발생합니다.
두 번째 !: Double(txtHeight.text!)와 Double(txtWeight.text!)는 문자열을 Double 타입으로 변환하는 시도입니다. 문자열이 숫자로 변환될 수 없는 경우 nil이 반환됩니다. 따라서 이 값을 다시 강제로 언래핑하여 Double 값을 가져옵니다. 이 경우에도 nil이라면 런타임 오류가 발생합니다.
<guard let을 사용하여 코드 수정>
guard let heightText = txtHeight.text,
let height = Double(heightText) else {
print("Height 입력값이 올바르지 않습니다.")
return
}
print("Height: \(height)")
guard let weightText = txtWeight.text,
let weight = Double(weightText) else {
print("Weight 입력값이 올바르지 않습니다.")
return
}
print("Weight: \(weight)")
//
// ViewController.swift
// BMI_kdh
//
// Created by 소프트웨어컴퓨터 on 2024/11/13.
//
import UIKit
class ViewController: UIViewController {
@IBOutlet weak var txtHeight: UITextField!
@IBOutlet weak var txtWeight: UITextField!
@IBOutlet weak var lblResult: UILabel!
@IBAction func calcBmi(_ sender: UIButton) {
if txtHeight.text == "" || txtWeight.text == "" {//값이 없으면 안내문이 뜨고 , 색을 red 로 지정함
lblResult.textColor = .red
lblResult.text = "키와 체중을 입력하세요!"
return
}else{
let weight = Double(txtWeight.text!)!
let height = Double(txtHeight.text!)!
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 = "저체중"
}
print("BMI:\(shortenedBmi), 판정:\(body)")
lblResult.text = "BMI:\(shortenedBmi), 판정: \(body)"
}
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
}
전체 선택후 ctrl +i : 소스 정렬
//
// ViewController.swift
// BMI_kdh
//
// Created by 소프트웨어컴퓨터 on 2024/11/13.
//
import UIKit
class ViewController: UIViewController {
@IBOutlet weak var txtHeight: UITextField! // 키 입력 필드
@IBOutlet weak var txtWeight: UITextField! // 체중 입력 필드
@IBOutlet weak var lblResult: UILabel! // 결과를 출력할 레이블
@IBAction func calcBmi(_ sender: UIButton) { // BMI 계산 버튼 클릭 시 호출되는 함수
// 입력값이 비어 있는지 확인
if txtHeight.text == "" || txtWeight.text == "" {
lblResult.textColor = .red // 경고 메시지 색상 설정
lblResult.text = "키와 체중을 입력하세요!" // 안내 메시지 출력
return // 함수 종료
} else {
// 입력된 키와 체중을 Double로 변환
let weight = Double(txtWeight.text!)!
let height = Double(txtHeight.text!)!
// BMI 계산 (kg/m²)
let bmi = weight / (height * height * 0.0001)
let shortenedBmi = String(format: "%.1f", bmi) // 소수점 1자리로 포맷팅
var body = "" // BMI 판정을 저장할 변수
var color = UIColor.white // 초기 배경색을 하얀색으로 설정
// BMI 값에 따른 판정 및 색상 설정
if bmi >= 40 {
color = UIColor(displayP3Red: 1.0, green: 0.0, blue: 0.0, alpha: 1.0) // 3단계 비만 (빨간색)
body = "3단계 비만"
} else if bmi >= 30 && bmi < 40 {
color = UIColor(displayP3Red: 0.7, green: 0.0, blue: 0.0, alpha: 1.0) // 2단계 비만 (어두운 빨간색)
body = "2단계 비만"
} else if bmi >= 25 && bmi < 30 {
color = UIColor(displayP3Red: 0.4, green: 0.0, blue: 0.0, alpha: 1.0) // 1단계 비만 (좀 더 어두운 빨간색)
body = "1단계 비만"
} else if bmi >= 18.5 && bmi < 25 {
color = UIColor(displayP3Red: 0.0, green: 0.0, blue: 1.0, alpha: 1.0) // 정상 (파란색)
body = "정상"
} else {
color = UIColor(displayP3Red: 0.0, green: 1.0, blue: 0.0, alpha: 1.0) // 저체중 (초록색)
body = "저체중"
}
// 결과 레이블의 배경색 설정
lblResult.backgroundColor = color
lblResult.clipsToBounds = true // 레이블의 경계선 처리
lblResult.layer.cornerRadius = 10 // 레이블의 모서리를 둥글게 설정
lblResult.text = "BMI:\(shortenedBmi), 판정: \(body)" // 결과 출력
}
}
override func viewDidLoad() {
super.viewDidLoad()
// 뷰가 로드된 후 추가 설정이 필요할 경우 여기에 작성
}
}
결과 나올때 결과에 따라 배경색이 바뀌는 코드 + 결과 레이블 둥글게하는 코드 추가
universal: 고해상도 ( 아이패드, 아이폰 사진 전부 가능하게하는 )
tab bar controller 선택하면 화면이 하나 더 생김
(apple hig: apple 디자인 가이드라인)
tab bar controller 화면을 ctrl누르고 드래그 후 view controllers 누르기
import UIKit
// 이미지 파일 이름을 저장하는 배열
var images = [ "01.png", "02.png", "03.png", "04.png", "05.png", "06.png" ]
class ViewController: UIViewController {
// 이미지 뷰와 페이지 컨트롤을 아울렛으로 연결
@IBOutlet var imgView: UIImageView!
@IBOutlet var pageControl: UIPageControl!
override func viewDidLoad() {
super.viewDidLoad()
// 뷰가 로드된 후 추가 설정
// 페이지 컨트롤의 페이지 수를 이미지 배열의 수로 설정
pageControl.numberOfPages = images.count
// 현재 페이지를 3으로 설정 (4번째 이미지)
pageControl.currentPage = 3
// 페이지 인디케이터 색상 설정
pageControl.pageIndicatorTintColor = UIColor.blue
pageControl.currentPageIndicatorTintColor = UIColor.yellow
// 초기 이미지 설정 (첫 번째 이미지)
imgView.image = UIImage(named: images[0])
}
// 페이지 컨트롤의 값이 변경될 때 호출되는 메서드
@IBAction func pageChange(_ sender: UIPageControl) {
// 현재 페이지에 해당하는 이미지를 이미지 뷰에 설정
imgView.image = UIImage(named: images[pageControl.currentPage])
}
}
10 탭 바 컨트롤러 이용해 여러 개의 뷰 넣기
-tabbar controller
화면 밑에 tab으로 다른 화면으로 빠르게 이동해줌
-navigation controller
앱에서 화면 간의 전환을 쉽게 만들기 위해 사용
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// 재사용 가능한 셀을 큐에서 가져옵니다. "myCell" 식별자를 사용합니다.
let cell = tableView.dequeueReusableCell(withIdentifier: "myCell", for: indexPath)
// items 배열에서 현재 행의 데이터로 텍스트 레이블을 설정합니다.
cell.textLabel?.text = items[(indexPath as NSIndexPath).row]
// itemsImageFile 배열에서 현재 행의 이미지로 이미지 뷰를 설정합니다.
cell.imageView?.image = UIImage(named: itemsImageFile[(indexPath as NSIndexPath).row])
// 구성된 셀을 반환합니다.
return cell
}
12 테이블 뷰 컨트롤러 이용해 할 일 목록 만들기
//
// TableViewController.swift
// Table
//
// Created by BeomGeun Lee on 2021.
//
import UIKit
// 아이템 목록과 이미지 파일 이름 배열
var items = ["책 구매", "철수와 약속", "스터디 준비하기"]
var itemsImageFile = ["cart.png", "clock.png", "pencil.png"]
class TableViewController: UITableViewController {
@IBOutlet var tvListView: UITableView! // 테이블 뷰 아울렛
override func viewDidLoad() {
super.viewDidLoad()
// 선택 상태를 유지하려면 주석 해제
// self.clearsSelectionOnViewWillAppear = false
// 내비게이션 바에 편집 버튼 추가
self.navigationItem.leftBarButtonItem = self.editButtonItem
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
// 뷰가 나타날 때 테이블 뷰를 갱신
tvListView.reloadData()
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
// 테이블 뷰의 섹션 수 반환
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// 섹션에 있는 행의 수 반환
return items.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// 재사용 가능한 셀을 큐에서 가져옴
let cell = tableView.dequeueReusableCell(withIdentifier: "myCell", for: indexPath)
// 해당 행의 텍스트와 이미지를 설정
cell.textLabel?.text = items[(indexPath as NSIndexPath).row]
cell.imageView?.image = UIImage(named: itemsImageFile[(indexPath as NSIndexPath).row])
return cell
}
// Override to support conditional editing of the table view.
// 셀 편집 가능 여부 설정
override func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
return true
}
// Override to support editing the table view.
override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
// 삭제 버튼 클릭 시 데이터 소스에서 해당 아이템 삭제
items.remove(at: (indexPath as NSIndexPath).row)
itemsImageFile.remove(at: (indexPath as NSIndexPath).row)
tableView.deleteRows(at: [indexPath], with: .fade) // 테이블 뷰에서 행 삭제
} else if editingStyle == .insert {
// 새로운 아이템 추가 시 처리 (현재는 구현 안 됨)
}
}
override func tableView(_ tableView: UITableView, titleForDeleteConfirmationButtonForRowAt indexPath: IndexPath) -> String? {
// 삭제 확인 버튼의 제목 설정
return "삭제"
}
// Override to support rearranging the table view.
override func tableView(_ tableView: UITableView, moveRowAt fromIndexPath: IndexPath, to: IndexPath) {
// 행 이동 처리
let itemToMove = items[(fromIndexPath as NSIndexPath).row]
let itemImageToMove = itemsImageFile[(fromIndexPath as NSIndexPath).row]
items.remove(at: (fromIndexPath as NSIndexPath).row)
itemsImageFile.remove(at: (fromIndexPath as NSIndexPath).row)
items.insert(itemToMove, at: (to as NSIndexPath).row)
itemsImageFile.insert(itemImageToMove, at: (to as NSIndexPath).row)
}
// Override to support conditional rearranging of the table view.
// 행 이동 가능 여부 설정
override func tableView(_ tableView: UITableView, canMoveRowAt indexPath: IndexPath) -> Bool {
return true
}
// MARK: - Navigation
// 내비게이션을 위한 준비 작업
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// segue.identifier가 "sgDetail"인 경우
if segue.identifier == "sgDetail" {
let cell = sender as! UITableViewCell // 선택된 셀
let indexPath = self.tvListView.indexPath(for: cell) // 셀의 인덱스 경로
let detailView = segue.destination as! DetailViewController // 목적지 뷰 컨트롤러
detailView.reciveItem(items[((indexPath! as NSIndexPath).row)]) // 선택된 아이템 전달
}
}
}
iOS 앱을 만들 때 가장 많이 사용하는 UI 요소
1. UILabel: 텍스트를 표시하는 데 사용됩니다. 주로 제목이나 설명을 나타낼 때 사용됩니다.
2. UIButton: 사용자와의 상호작용을 위한 버튼입니다. 다양한 스타일과 동작을 정의할 수 있습니다.
3. UIImageView: 이미지를 표시하는 데 사용됩니다. 사진이나 아이콘 등 다양한 이미지를 표시할 수 있습니다.
4. UITableView: 리스트 형태로 데이터를 표시할 때 사용됩니다. 스크롤이 가능한 목록을 만들 수 있습니다.
13 음악 재생하고 녹음하기
-
AVAudioPlayer 사용하기 위해선
import AVFoundation추가해야됨
import UIKit
import AVFoundation
class ViewController: UIViewController, AVAudioPlayerDelegate, AVAudioRecorderDelegate {
var audioPlayer: AVAudioPlayer! // 오디오 재생을 위한 AVAudioPlayer
var audioFile: URL! // 오디오 파일 URL
let MAX_VOLUME: Float = 10.0 // 최대 볼륨 값
var progressTimer: Timer! // 재생 진행 상태를 업데이트하기 위한 타이머
// 타이머 업데이트 메서드를 위한 셀렉터
let timePlayerSelector: Selector = #selector(ViewController.updatePlayTime)
let timeRecordSelector: Selector = #selector(ViewController.updateRecordTime)
// UI 아울렛 변수들
@IBOutlet var pvProgressPlay: UIProgressView! // 재생 진행 상태를 표시하는 프로그레스 뷰
@IBOutlet var lblCurrentTime: UILabel! // 현재 재생 시간 레이블
@IBOutlet var lblEndTime: UILabel! // 총 재생 시간 레이블
@IBOutlet var btnPlay: UIButton! // 재생 버튼
@IBOutlet var btnPause: UIButton! // 일시 정지 버튼
@IBOutlet var btnStop: UIButton! // 정지 버튼
@IBOutlet var slVolume: UISlider! // 볼륨 조절 슬라이더
@IBOutlet var btnRecord: UIButton! // 녹음 버튼
@IBOutlet var lblRecordTime: UILabel! // 녹음 시간 레이블
var audioRecorder: AVAudioRecorder! // 오디오 녹음을 위한 AVAudioRecorder
var isRecordMode = false // 녹음 모드 여부
override func viewDidLoad() {
super.viewDidLoad()
// 뷰 로드 후 추가 설정
selectAudioFile() // 오디오 파일 선택
if !isRecordMode {
initPlay() // 재생 초기화
btnRecord.isEnabled = false // 녹음 버튼 비활성화
lblRecordTime.isEnabled = false // 녹음 시간 레이블 비활성화
} else {
initRecord() // 녹음 초기화
}
}
func selectAudioFile() {
// 녹음 모드에 따라 오디오 파일 선택
if !isRecordMode {
audioFile = Bundle.main.url(forResource: "Sicilian_Breeze", withExtension: "mp3") // 재생할 파일
} else {
let documentDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
audioFile = documentDirectory.appendingPathComponent("recordFile.m4a") // 녹음 파일 경로
}
}
func initRecord() {
// 녹음을 위한 설정
let recordSettings = [
AVFormatIDKey: NSNumber(value: kAudioFormatAppleLossless as UInt32),
AVEncoderAudioQualityKey: AVAudioQuality.max.rawValue,
AVEncoderBitRateKey: 320000,
AVNumberOfChannelsKey: 2,
AVSampleRateKey: 44100.0
] as [String: Any]
do {
audioRecorder = try AVAudioRecorder(url: audioFile, settings: recordSettings) // AVAudioRecorder 초기화
} catch let error as NSError {
print("Error-initRecord: \(error)") // 오류 처리
}
audioRecorder.delegate = self // 델리게이트 설정
slVolume.value = 1.0 // 기본 볼륨 설정
audioPlayer.volume = slVolume.value // 재생기 볼륨 설정
lblEndTime.text = convertNSTimeInterval2String(0) // 종료 시간 초기화
lblCurrentTime.text = convertNSTimeInterval2String(0) // 현재 시간 초기화
setPlayButtons(false, pause: false, stop: false) // 버튼 상태 설정
let session = AVAudioSession.sharedInstance() // 오디오 세션 생성
do {
try AVAudioSession.sharedInstance().setCategory(.playAndRecord, mode: .default) // 카테고리 설정
try AVAudioSession.sharedInstance().setActive(true) // 세션 활성화
} catch let error as NSError {
print("Error-setCategory: \(error)") // 오류 처리
}
}
func initPlay() {
// 재생을 위한 초기 설정
do {
audioPlayer = try AVAudioPlayer(contentsOf: audioFile) // AVAudioPlayer 초기화
} catch let error as NSError {
print("Error-initPlay: \(error)") // 오류 처리
}
slVolume.maximumValue = MAX_VOLUME // 슬라이더 최대값 설정
slVolume.value = 1.0 // 기본 볼륨 설정
pvProgressPlay.progress = 0 // 프로그레스 뷰 초기화
audioPlayer.delegate = self // 델리게이트 설정
audioPlayer.prepareToPlay() // 재생 준비
audioPlayer.volume = slVolume.value // 볼륨 설정
lblEndTime.text = convertNSTimeInterval2String(audioPlayer.duration) // 종료 시간 표시
lblCurrentTime.text = convertNSTimeInterval2String(0) // 현재 시간 초기화
setPlayButtons(true, pause: false, stop: false) // 버튼 상태 설정
}
func setPlayButtons(_ play: Bool, pause: Bool, stop: Bool) {
// 버튼 활성화 상태 설정
btnPlay.isEnabled = play
btnPause.isEnabled = pause
btnStop.isEnabled = stop
}
func convertNSTimeInterval2String(_ time: TimeInterval) -> String {
// NSTimeInterval을 문자열로 변환
let min = Int(time / 60)
let sec = Int(time.truncatingRemainder(dividingBy: 60))
let strTime = String(format: "%02d:%02d", min, sec)
return strTime
}
@IBAction func btnPlayAudio(_ sender: UIButton) {
// 재생 버튼 클릭 시 호출
audioPlayer.play() // 오디오 재생
setPlayButtons(false, pause: true, stop: true) // 버튼 상태 설정
progressTimer = Timer.scheduledTimer(timeInterval: 0.1, target: self, selector: timePlayerSelector, userInfo: nil, repeats: true) // 타이머 시작
}
@objc func updatePlayTime() {
// 재생 시간 업데이트
lblCurrentTime.text = convertNSTimeInterval2String(audioPlayer.currentTime) // 현재 시간 레이블 업데이트
pvProgressPlay.progress = Float(audioPlayer.currentTime / audioPlayer.duration) // 프로그레스 뷰 업데이트
}
@IBAction func btnPauseAudio(_ sender: UIButton) {
// 일시 정지 버튼 클릭 시 호출
audioPlayer.pause() // 오디오 일시 정지
setPlayButtons(true, pause: false, stop: true) // 버튼 상태 설정
}
@IBAction func btnStopAudio(_ sender: UIButton) {
// 정지 버튼 클릭 시 호출
audioPlayer.stop() // 오디오 정지
audioPlayer.currentTime = 0 // 재생 시간 초기화
lblCurrentTime.text = convertNSTimeInterval2String(0) // 현재 시간 레이블 초기화
setPlayButtons(true, pause: false, stop: false) // 버튼 상태 설정
progressTimer.invalidate() // 타이머 중지
}
@IBAction func slChangeVolume(_ sender: UISlider) {
// 볼륨 슬라이더 값 변경 시 호출
audioPlayer.volume = slVolume.value // 오디오 볼륨 설정
}
func audioPlayerDidFinishPlaying(_ player: AVAudioPlayer, successfully flag: Bool) {
// 오디오 재생 완료 시 호출
progressTimer.invalidate() // 타이머 중지
setPlayButtons(true, pause: false, stop: false) // 버튼 상태 설정
}
@IBAction func swRecordMode(_ sender: UISwitch) {
// 녹음 모드 스위치 변경 시 호출
if sender.isOn {
audioPlayer.stop() // 재생 중지
audioPlayer.currentTime = 0 // 재생 시간 초기화
lblRecordTime.text = convertNSTimeInterval2String(0) // 녹음 시간 초기화
isRecordMode = true // 녹음 모드 활성화
btnRecord.isEnabled = true // 녹음 버튼 활성화
lblRecordTime.isEnabled = true // 녹음 시간 레이블 활성화
} else {
isRecordMode = false // 녹음 모드 비활성화
btnRecord.isEnabled = false // 녹음 버튼 비활성화
lblRecordTime.isEnabled = false // 녹음 시간 레이블 비활성화
lblRecordTime.text = convertNSTimeInterval2String(0) // 녹음 시간 초기화
}
selectAudioFile() // 오디오 파일 선택
if !isRecordMode {
initPlay() // 재생 초기화
} else
14 비디오 재생 앱 만들기
//
// ViewController.swift
// MoviePlayer
//
// Created by Ho-Jeong Song on 2021/11/26.
//
import UIKit
import AVKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// 뷰가 로드된 후 추가 설정
}
@IBAction func btnPlayInternalMovie(_ sender: UIButton) {
// 내부 파일 mp4 재생
let filePath: String? = Bundle.main.path(forResource: "FastTyping", ofType: "mp4") // 내부 파일 경로
let url = NSURL(fileURLWithPath: filePath!) // NSURL 객체 생성
playVideo(url: url) // 비디오 재생 함수 호출
}
@IBAction func btnPlayerExternalMovie(_ sender: UIButton) {
// 외부 파일 mp4 재생
let url = NSURL(string: "https://dl.dropboxusercontent.com/s/e38auz050w2mvud/Fireworks.mp4")! // 외부 URL 생성
playVideo(url: url) // 비디오 재생 함수 호출
}
private func playVideo(url: NSURL) {
// 비디오 재생을 위한 함수
let playerController = AVPlayerViewController() // 비디오 플레이어 컨트롤러 생성
let player = AVPlayer(url: url as URL) // AVPlayer 객체 생성
playerController.player = player // 플레이어를 플레이어 컨트롤러에 설정
self.present(playerController, animated: true) {
player.play() // 비디오 재생 시작
}
}
}
17 탭과 터치 사용해 스케치 앱 만들기
import UIKit
class ViewController: UIViewController {
@IBOutlet var imgView: UIImageView! // 그림을 그릴 이미지 뷰
var lastPoint: CGPoint! // 마지막 터치 위치
var lineSize: CGFloat = 2.0 // 선의 두께
var lineColor = UIColor.black.cgColor // 선의 색상
override func viewDidLoad() {
super.viewDidLoad()
// 뷰가 로드된 후 추가 설정
}
@IBAction func btnClearImageView(_ sender: UIButton) {
// 이미지 뷰를 지우는 버튼 액션
imgView.image = nil // 이미지 뷰의 이미지를 nil로 설정
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
// 터치가 시작될 때 호출
let touch = touches.first! as UITouch // 첫 번째 터치 가져오기
lastPoint = touch.location(in: imgView) // 마지막 터치 위치 설정
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
// 터치가 이동할 때 호출
UIGraphicsBeginImageContext(imgView.frame.size) // 새로운 그래픽 컨텍스트 시작
UIGraphicsGetCurrentContext()?.setStrokeColor(lineColor) // 선 색상 설정
UIGraphicsGetCurrentContext()?.setLineCap(CGLineCap.round) // 선 끝 모양 설정
UIGraphicsGetCurrentContext()?.setLineWidth(lineSize) // 선 두께 설정
let touch = touches.first! as UITouch // 첫 번째 터치 가져오기
let currPoint = touch.location(in: imgView) // 현재 터치 위치
// 현재 이미지를 그래픽 컨텍스트에 그리기
imgView.image?.draw(in: CGRect(x: 0, y: 0, width: imgView.frame.size.width, height: imgView.frame.size.height))
// 선을 그리기
UIGraphicsGetCurrentContext()?.move(to: CGPoint(x: lastPoint.x, y: lastPoint.y)) // 시작점 설정
UIGraphicsGetCurrentContext()?.addLine(to: CGPoint(x: currPoint.x, y: currPoint.y)) // 끝점 설정
UIGraphicsGetCurrentContext()?.strokePath() // 선 그리기
imgView.image = UIGraphicsGetImageFromCurrentImageContext() // 그린 이미지를 이미지 뷰에 설정
UIGraphicsEndImageContext() // 그래픽 컨텍스트 종료
lastPoint = currPoint // 마지막 위치 업데이트
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
// 터치가 끝날 때 호출
UIGraphicsBeginImageContext(imgView.frame.size) // 새로운 그래픽 컨텍스트 시작
UIGraphicsGetCurrentContext()?.setStrokeColor(lineColor) // 선 색상 설정
UIGraphicsGetCurrentContext()?.setLineCap(CGLineCap.round) // 선 끝 모양 설정
UIGraphicsGetCurrentContext()?.setLineWidth(lineSize) // 선 두께 설정
// 현재 이미지를 그래픽 컨텍스트에 그리기
imgView.image?.draw(in: CGRect(x: 0, y: 0, width: imgView.frame.size.width, height: imgView.frame.size.height))
// 마지막 터치 위치에서 선 그리기
UIGraphicsGetCurrentContext()?.move(to: CGPoint(x: lastPoint.x, y: lastPoint.y))
UIGraphicsGetCurrentContext()?.addLine(to: CGPoint(x: lastPoint.x, y: lastPoint.y)) // 마지막 점에서 자신으로 선을 그리기
UIGraphicsGetCurrentContext()?.strokePath() // 선 그리기
imgView.image = UIGraphicsGetImageFromCurrentImageContext() // 그린 이미지를 이미지 뷰에 설정
UIGraphicsEndImageContext() // 그래픽 컨텍스트 종료
}
override func motionEnded(_ motion: UIEvent.EventSubtype, with event: UIEvent?) {
// 흔들림 제스처가 끝날 때 호출
if motion == .motionShake {
imgView.image = nil // 흔들림 제스처로 이미지 뷰 지우기
}
}
}
//
// ViewController.swift
// Sketch
//
// Created by Ho-Jeong Song on 2021/12/01.
//
import UIKit
class ViewController: UIViewController {
@IBOutlet var imgView: UIImageView! // 그림을 그릴 이미지 뷰
@IBOutlet var txtLineSize: UITextField! // 선의 두께를 입력받는 텍스트 필드
var lastPoint: CGPoint! // 마지막 터치 위치
var lineSize: CGFloat = 2.0 // 선의 기본 두께
var lineColor = UIColor.red.cgColor // 선의 기본 색상
override func viewDidLoad() {
super.viewDidLoad()
// 뷰가 로드된 후 추가 설정
txtLineSize.text = String(Int(lineSize)) // 현재 선 두께를 텍스트 필드에 표시
}
@IBAction func btnClearImageView(_ sender: UIButton) {
// 이미지 뷰를 지우는 버튼 액션
imgView.image = nil // 이미지 뷰의 이미지를 nil로 설정
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
// 터치가 시작될 때 호출
let touch = touches.first! as UITouch // 첫 번째 터치 가져오기
lastPoint = touch.location(in: imgView) // 마지막 터치 위치 설정
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
// 터치가 이동할 때 호출
UIGraphicsBeginImageContext(imgView.frame.size) // 새로운 그래픽 컨텍스트 시작
UIGraphicsGetCurrentContext()?.setStrokeColor(lineColor) // 선 색상 설정
UIGraphicsGetCurrentContext()?.setLineCap(CGLineCap.round) // 선 끝 모양 설정
UIGraphicsGetCurrentContext()?.setLineWidth(lineSize) // 선 두께 설정
let touch = touches.first! as UITouch // 첫 번째 터치 가져오기
let currPoint = touch.location(in: imgView) // 현재 터치 위치
// 이미지 뷰의 현재 내용을 그래픽 컨텍스트에 그리기
imgView.image?.draw(in: CGRect(x: 0, y: 0, width: imgView.frame.size.width, height: imgView.frame.size.height))
// 선 그리기
UIGraphicsGetCurrentContext()?.move(to: CGPoint(x: lastPoint.x, y: lastPoint.y)) // 시작점 설정
UIGraphicsGetCurrentContext()?.addLine(to: CGPoint(x: currPoint.x, y: currPoint.y)) // 끝점 설정
UIGraphicsGetCurrentContext()?.strokePath() // 선 그리기
imgView.image = UIGraphicsGetImageFromCurrentImageContext() // 그린 이미지를 이미지 뷰에 설정
UIGraphicsEndImageContext() // 그래픽 컨텍스트 종료
lastPoint = currPoint // 마지막 위치 업데이트
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
// 터치가 끝날 때 호출
UIGraphicsBeginImageContext(imgView.frame.size) // 새로운 그래픽 컨텍스트 시작
UIGraphicsGetCurrentContext()?.setStrokeColor(lineColor) // 선 색상 설정
UIGraphicsGetCurrentContext()?.setLineCap(CGLineCap.round) // 선 끝 모양 설정
UIGraphicsGetCurrentContext()?.setLineWidth(lineSize) // 선 두께 설정
// 이미지 뷰의 현재 내용을 그래픽 컨텍스트에 그리기
imgView.image?.draw(in: CGRect(x: 0, y: 0, width: imgView.frame.size.width, height: imgView.frame.size.height))
// 마지막 터치 위치에서 선 그리기
UIGraphicsGetCurrentContext()?.move(to: CGPoint(x: lastPoint.x, y: lastPoint.y))
UIGraphicsGetCurrentContext()?.addLine(to: CGPoint(x: lastPoint.x, y: lastPoint.y)) // 마지막 점에서 자신으로 선 그리기
UIGraphicsGetCurrentContext()?.strokePath() // 선 그리기
imgView.image = UIGraphicsGetImageFromCurrentImageContext() // 그린 이미지를 이미지 뷰에 설정
UIGraphicsEndImageContext() // 그래픽 컨텍스트 종료
}
override func motionEnded(_ motion: UIEvent.EventSubtype, with event: UIEvent?) {
// 흔들림 제스처가 끝날 때 호출
if motion == .motionShake {
imgView.image = nil // 흔들림 제스처로 이미지 뷰 지우기
}
}
@IBAction func txtEditChange(_ sender: UITextField) {
// 텍스트 필드의 내용이 변경될 때 호출
if txtLineSize.text != "" {
lineSize = CGFloat(Int(txtLineSize.text!)!) // 입력된 값을 선 두께로 설정
}
}
@IBAction func txtDidEndOnExit(_ sender: UITextField) {
// 텍스트 필드에서 입력이 끝날 때 호출
lineSize = CGFloat(Int(txtLineSize.text!)!) // 입력된 값을 선 두께로 설정
}
@IBAction func txtTouchDown(_ sender: UITextField) {
// 텍스트 필드가 터치될 때 호출
txtLineSize.selectAll(UITextField.self) // 텍스트 필드의 모든 텍스트 선택
}
@IBAction func btnChangeLineColorBlack(_ sender: UIButton) {
// 검은색 버튼 클릭 시 호출
lineColor = UIColor.black.cgColor // 선 색상을 검은색으로 설정
}
@IBAction func btnChangeLineColorRed(_ sender: UIButton) {
// 빨간색 버튼 클릭 시 호출
lineColor = UIColor.red.cgColor // 선 색상을 빨간색으로 설정
}
@IBAction func btnChangeLineColorGreen(_ sender: UIButton) {
// 초록색 버튼 클릭 시 호출
lineColor = UIColor.green.cgColor // 선 색상을 초록색으로 설정
}
@IBAction func btnChangeLineColorBlue(_ sender: UIButton) {
// 파란색 버튼 클릭 시 호출
lineColor = UIColor.blue.cgColor // 선 색상을 파란색으로 설정
}
}
BMI 앱 기획서 1. 앱 개요 1.1 앱 이름 HealthCalc: BMI Calculator 1.2 앱 설명 HealthCalc는 사용자가 자신의 BMI(체질량지수)를 쉽게 계산하고, 건강을 관리하는 데 도움을 주는 앱입니다. 사용자 친화적인 인터페이스와 다양한 기능을 통해 체중 관리와 건강한 생활 습관을 촉진합니다. 2. 주요 기능 2.1 사용자 입력 **키(cm)**와 체중(kg) 입력을 위한 텍스트 필드 제공 입력 유효성 검사: 숫자가 아닌 경우 오류 메시지 표시 2.2 BMI 계산 사용자가 입력한 값으로 BMI를 계산하고, 결과를 실시간으로 업데이트 계산된 BMI 값에 따라 건강 상태 메시지 제공 (예: 저체중, 정상 체중, 과체중, 비만) 2.3 결과 저장 및 기록 사용자의 BMI 계산 기록을 저장하고, 이전 기록을 확인할 수 있는 기능 제공 기록된 데이터를 기반으로 그래프 또는 차트로 시각화하여 건강 변화 추적 가능 2.4 추가 기능 건강 팁: BMI에 따라 맞춤형 건강 팁 제공 (예: 운동 추천, 식단 조절) 목표 설정: 사용자가 목표 체중을 설정하고, 이를 달성하기 위한 계획 수립 알림 기능: 정기적으로 체중 측정을 하도록 알림 설정 2.5 다국어 지원 다양한 언어로 앱을 제공하여 글로벌 사용자층 확보 3. UI/UX 디자인 3.1 디자인 원칙 심플하고 직관적인 UI: 사용자가 쉽게 이해하고 사용할 수 있도록 간결한 디자인 일관된 색상 및 폰트: 건강과 관련된 차분한 색상 사용 (예: 초록색, 파란색) 3.2 화면 구성 홈 화면: 키와 체중 입력 필드, 계산 버튼, 결과 표시 영역 결과 화면: BMI 결과, 건강 상태 메시지, 이전 기록 버튼 기록 화면: 과거 BMI 기록 목록, 그래프 표시 설정 화면: 알림 설정, 언어 선택, 도움말 4. 경쟁 분석 4.1 기존 인기 앱 분석 MyFitnessPal: 체중 관리와 영양 추적에 강점을 가진 앱. 다양한 기능과 사용자 커뮤니티 제공. BMI Calculator: 간단하고 직관적인 BMI 계산 기능. 사용자 친화적인 인터페이스. Lose It!: 체중 감량 목표 설정 및 추적 기능 제공. 사용자 맞춤형 다이어트 계획. 4.2 차별점 HealthCalc는 BMI 계산뿐만 아니라, 사용자 맞춤형 건강 팁과 목표 설정 기능을 통해 보다 포괄적인 건강 관리 솔루션을 제공합니다. 5. 마케팅 전략 5.1 타겟 사용자 건강 관리를 원하는 일반 사용자 체중 감량 및 운동을 목표로 하는 사용자 5.2 홍보 전략 소셜 미디어 플랫폼을 통한 광고 및 캠페인 건강 관련 블로그 및 웹사이트와의 협업 사용자 후기를 통한 신뢰성 확보 6. 개발 계획 6.1 기술 스택 프론트엔드: Swift, UIKit 백엔드: Firebase (데이터 저장 및 사용자 인증) 디자인 도구: Figma 또는 Sketch 6.2 개발 일정 1개월: 기획 및 디자인 2개월: 개발 및 내부 테스트 1개월: 베타 테스트 및 피드백 반영 1개월: 출시 준비 및 마케팅 7. 예상 비용 개발 인력, 디자인, 마케팅 비용 등을 포함한 예산 계획 수립
1. ui디자인
2.outlet
3.action
4. connections inspector로 outlet이나 action 이 한번만 연결된 것인지 확인
5.action에 소스코드 작성
이미지는 assets.xcassets에 넣고 alt키를 눌러서 옮기는 이유는 선명하게(?)하기 위해
Decimal pad
출처:
Do it! 스위프트로 아이폰 앱 만들기 입문, 송호정, 이범근 저,이지스퍼블리싱, 2023년 01월 20일
---------------------------------------- 02 Hello World 앱 만들며 Xcode에 완벽 적응하기 03 원하는 이미지 화면에 출력하기 - 이미지 뷰 04 데이트 피커 사용해 날짜 선택하기 05 피커 뷰 사용해 원하는 항목 선택하기 06 얼럿 사용해 경고 표시하기 07 웹 뷰로 간단한 웹 브라우저 만들기 08 맵 뷰로 지도 나타내기 09 페이지 이동하기 - 페이지 컨트롤 10 탭 바 컨트롤러 이용해 여러 개의 뷰 넣기 11 내비게이션 컨트롤러 이용해 화면 전환하기 12 테이블 뷰 컨트롤러 이용해 할 일 목록 만들기 13 음악 재생하고 녹음하기 14 비디오 재생 앱 만들기 15 카메라와 포토 라이브러리에서 미디어 가져오기 16 코어 그래픽스로 화면에 그림 그리기 17 탭과 터치 사용해 스케치 앱 만들기 18 스와이프 제스처 사용하기 19 핀치 제스처 사용해 사진을 확대/축소하기
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// UILabel 생성
let myLabel = UILabel()
// 레이블 속성 설정
myLabel.text = "안녕하세요, iOS!"
myLabel.textColor = .black
myLabel.font = UIFont.systemFont(ofSize: 24)
myLabel.textAlignment = .center
// 레이블의 크기와 위치 설정
myLabel.frame = CGRect(x: 0, y: 0, width: 300, height: 50)
myLabel.center = view.center // 화면 중앙에 배치
// 레이블을 뷰에 추가
view.addSubview(myLabel)
}
}
aspect fit으로 하는게 좋음
import UIKit
class ViewController: UIViewController {
var x :Int = 0
@IBOutlet weak var labelnumber: UILabel!
@IBOutlet weak var lblHello: UILabel!
@IBAction func btnDown(_ sender: UIButton) {
x = x-1 //마이너스 버튼 누르면 숫자가 줄어든다
labelnumber.text = String(x)
}
@IBAction func btnUp(_ sender: UIButton) {
x = x+1//플러스 버튼 누르면 S가 숫자로 바뀌고 숫자가 늘어남
labelnumber.text = String(x)
}
@IBOutlet weak var txtName: UITextField!
@IBAction func btnSend(_ sender: UIButton) {
lblHello.text = "Hi, " + txtName.text!
print(lblHello.text, txtName.text)
}
@IBAction func btnReset(_ sender: UIButton) {
lblHello.textColor = .systemBlue
lblHello.text = "안녕하세요!"
txtName.text = ""
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
}
03 원하는 이미지 화면에 출력하기 - 이미지 뷰
아래는 주어진 Swift 코드에 대한 주석입니다. 각 부분의 기능을 설명합니다.
```swift
//
// ViewController.swift
// ImageView
//
// Created by Ho-Jeong Song on 2021/11/23.
//
import UIKit
// ViewController 클래스 정의
class ViewController: UIViewController {
// 이미지 확대 여부를 나타내는 변수
var isZoom = false
// 이미지 온, 오프 상태에 대한 UIImage 변수
var imgOn: UIImage?
var imgOff: UIImage?
// IBOutlet으로 연결된 UIImageView와 UIButton
@IBOutlet var imgView: UIImageView!
@IBOutlet var btnResize: UIButton!
// 뷰가 로드될 때 호출되는 메서드
override func viewDidLoad() {
super.viewDidLoad()
// 이미지 파일을 로드하여 변수에 저장
imgOn = UIImage(named: "lamp_on.png")
imgOff = UIImage(named: "lamp_off.png")
// 초기 이미지로 imgOn 설정
imgView.image = imgOn
}
// UIButton 클릭 시 호출되는 액션 메서드
@IBAction func btnResizeImage(_ sender: UIButton) {
let scale: CGFloat = 2.0 // 확대/축소 비율
var newWidth: CGFloat, newHeight: CGFloat
// 현재 확대 상태에 따라 이미지 뷰의 크기를 조정
if (isZoom) { // true일 경우 (이미지가 확대된 상태)
newWidth = imgView.frame.width / scale // 너비 축소
newHeight = imgView.frame.height / scale // 높이 축소
// 버튼의 제목을 "확대"로 변경
btnResize.setTitle("확대", for: .normal)
}
else { // false일 경우 (이미지가 축소된 상태)
newWidth = imgView.frame.width * scale // 너비 확대
newHeight = imgView.frame.height * scale // 높이 확대
// 버튼의 제목을 "축소"로 변경
btnResize.setTitle("축소", for: .normal)
}
// 이미지 뷰의 크기를 새로운 크기로 설정
imgView.frame.size = CGSize(width: newWidth, height: newHeight)
// isZoom 상태를 반전시켜 다음 클릭 시 동작 변경
isZoom = !isZoom
}
// UISwitch 클릭 시 호출되는 액션 메서드
@IBAction func switchImageOnOff(_ sender: UISwitch) {
// 스위치가 켜져 있으면 imgOn 이미지 설정
if sender.isOn {
imgView.image = imgOn
} else { // 스위치가 꺼져 있으면 imgOff 이미지 설정
imgView.image = imgOff
}
}
}
```
### 주석 요약
- 이 코드는 iOS 앱의 ViewController를 정의하고, 이미지 뷰와 버튼, 스위치를 통해 이미지를 확대/축소하거나 변경하는 기능을 제공합니다.
- `viewDidLoad` 메서드는 뷰가 로드될 때 초기 설정을 담당합니다.
- `btnResizeImage` 메서드는 버튼 클릭 시 이미지를 확대하거나 축소합니다.
- `switchImageOnOff` 메서드는 스위치의 상태에 따라 이미지를 변경합니다.
이런 자료를 참고했어요.
[1] velog - [Swift] ViewController 화면전환 방법 (https://velog.io/@5n_tak/Swift-ViewController-%ED%99%94%EB%A9%B4%EC%A0%84%ED%99%98-%EB%B0%A9%EB%B2%95)
[2] 티스토리 - [iOS/Swift] ViewController 화면 전환 방법 3가지 (https://eunoia3jy.tistory.com/210)
[3] 티스토리 - [iOS/swift] 이미지 뷰 (ImageView) 앱 만들기 - 무니봇 IT 블로그 (https://moonibot.tistory.com/4)
[4] 네이버 블로그 - [iOS] ViewController의 특징과 생명주기 - 네이버 블로그 (https://m.blog.naver.com/doctor-kick/222424663918)
뤼튼 사용하러 가기 > https://agent.wrtn.ai/5xb91l
04 데이트 피커 사용해 날짜 선택하기
06 얼럿 사용해 경고 표시하기
import UIKit
class ViewController: UIViewController {
let imgOn = UIImage(named: "lamp-on.png")
let imgOff = UIImage(named: "lamp-off.png")
let imgRemove = UIImage(named: "lamp-remove.png")
var isLampOn = true
@IBOutlet var lampImg: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
lampImg.image = imgOn
}
@IBAction func btnLampOn(_ sender: UIButton) {
if(isLampOn==true) {
let lampOnAlert = UIAlertController(title: "경고", message: "현재 On 상태입니다", preferredStyle: UIAlertController.Style.alert)
let onAction = UIAlertAction(title: "네, 알겠습니다.", style: UIAlertAction.Style.default, handler: nil)
lampOnAlert.addAction(onAction)
present(lampOnAlert, animated: true, completion: nil)
} else {
lampImg.image = imgOn
isLampOn=true
}
}
@IBAction func btnLanpOff(_ sender: UIButton) {
if isLampOn {
let lampOffAlert = UIAlertController(title: "램프 끄기", message: "램프를 끄시겠습니까?", preferredStyle: UIAlertController.Style.alert)
let offAction = UIAlertAction(title: "네", style: UIAlertAction.Style.default, handler: {
ACTION in self.lampImg.image = self.imgOff
self.isLampOn=false
})
let cancelAction = UIAlertAction(title: "아니오", style: UIAlertAction.Style.default, handler: nil)
lampOffAlert.addAction(offAction)
lampOffAlert.addAction(cancelAction)
present(lampOffAlert, animated: true, completion: nil)
}
}
@IBAction func btnLampRemove(_ sender: UIButton) {
let lampRemoveAlert = UIAlertController(title: "램프 제거", message: "램프를 제거하시겠습니까?", preferredStyle: UIAlertController.Style.alert)
let offAction = UIAlertAction(title: "아니오, 끕니다(off).", style: UIAlertAction.Style.default, handler: {
ACTION in self.lampImg.image = self.imgOff
self.isLampOn=false
})
let onAction = UIAlertAction(title: "아니오, 켭니다(on).", style: UIAlertAction.Style.default) {
ACTION in self.lampImg.image = self.imgOn
self.isLampOn=true
}
let removeAction = UIAlertAction(title: "네, 제거합니다.", style: UIAlertAction.Style.destructive, handler: {
ACTION in self.lampImg.image = self.imgRemove
self.isLampOn=false
})
lampRemoveAlert.addAction(offAction)
lampRemoveAlert.addAction(onAction)
lampRemoveAlert.addAction(removeAction)
present(lampRemoveAlert, animated: true, completion: nil)
}
}
import UIKit // UIKit 프레임워크를 임포트하여 UI 관련 기능을 사용할 수 있도록 함
import MapKit // MapKit 프레임워크를 임포트하여 지도 관련 기능을 사용할 수 있도록 함
class ViewController: UIViewController, CLLocationManagerDelegate {
// UIViewController를 상속받고, CLLocationManagerDelegate 프로토콜을 채택
@IBOutlet var myMap: MKMapView! // 지도 뷰를 연결하는 아울렛
@IBOutlet var lblLocationInfo1: UILabel! // 위치 정보를 표시할 레이블 1
@IBOutlet var lblLocationInfo2: UILabel! // 위치 정보를 표시할 레이블 2
let locationManager = CLLocationManager() // 위치 관리 객체 생성
override func viewDidLoad() {
super.viewDidLoad() // 부모 클래스의 viewDidLoad 호출
// 뷰가 로드된 후 추가 설정을 수행
lblLocationInfo1.text = "" // 레이블 1 초기화
lblLocationInfo2.text = "" // 레이블 2 초기화
locationManager.delegate = self // 위치 관리자의 델리게이트를 현재 뷰 컨트롤러로 설정
locationManager.desiredAccuracy = kCLLocationAccuracyBest // 위치 정확도를 최대로 설정
locationManager.requestWhenInUseAuthorization() // 앱 사용 중 위치 권한 요청
locationManager.startUpdatingLocation() // 위치 업데이트 시작
myMap.showsUserLocation = true // 사용자 위치 표시 활성화
}
func goLocation(latitudeValue: CLLocationDegrees, longitudeValue: CLLocationDegrees, delta span: Double) -> CLLocationCoordinate2D {
let pLocation = CLLocationCoordinate2DMake(latitudeValue, longitudeValue) // 위도와 경도로 CLLocationCoordinate2D 객체 생성
let spanValue = MKCoordinateSpan(latitudeDelta: span, longitudeDelta: span) // 줌 레벨을 설정하는 span 객체 생성
let pRegion = MKCoordinateRegion(center: pLocation, span: spanValue) // 중심과 줌 레벨로 MKCoordinateRegion 객체 생성
myMap.setRegion(pRegion, animated: true) // 지도의 지역을 설정하고 애니메이션 효과 적용
return pLocation // 생성한 위치 반환
}
func setAnnotation(latitudeValue: CLLocationDegrees, longitudeValue: CLLocationDegrees, delta span: Double, title strTitle: String, subtitle strSubtitle: String) {
let annotation = MKPointAnnotation() // 새 주석(annotation) 객체 생성
annotation.coordinate = goLocation(latitudeValue: latitudeValue, longitudeValue: longitudeValue, delta: span) // 주석의 좌표 설정
annotation.title = strTitle // 주석의 제목 설정
annotation.subtitle = strSubtitle // 주석의 부제 설정
myMap.addAnnotation(annotation) // 지도에 주석 추가
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let pLocation = locations.last // 가장 최근의 위치 정보 가져오기
_ = goLocation(latitudeValue: (pLocation?.coordinate.latitude)!, longitudeValue: (pLocation?.coordinate.longitude)!, delta: 0.01) // 위치를 지도에 설정
CLGeocoder().reverseGeocodeLocation(pLocation!, completionHandler: { (placemarks, error) -> Void in // 역 지오코딩을 통해 주소 정보 가져오기
let pm = placemarks!.first // 첫 번째 placemark 가져오기
let country = pm!.country // 국가 정보 가져오기
var address: String = country! // 주소 초기화 (국가 포함)
if pm!.locality != nil { // 지역 정보가 있는 경우
address += " " // 공백 추가
address += pm!.locality! // 지역 정보 추가
}
if pm!.thoroughfare != nil { // 도로 정보가 있는 경우
address += " " // 공백 추가
address += pm!.thoroughfare! // 도로 정보 추가
}
self.lblLocationInfo1.text = "현재 위치" // 레이블 1에 현재 위치 텍스트 설정
self.lblLocationInfo2.text = address // 레이블 2에 주소 텍스트 설정
})
locationManager.stopUpdatingLocation() // 위치 업데이트 중지
}
@IBAction func sgChangeLocation(_ sender: UISegmentedControl) {
if sender.selectedSegmentIndex == 0 { // 첫 번째 세그먼트 선택 시
self.lblLocationInfo1.text = "" // 레이블 1 초기화
self.lblLocationInfo2.text = "" // 레이블 2 초기화
locationManager.startUpdatingLocation() // 위치 업데이트 시작
} else if sender.selectedSegmentIndex == 1 { // 두 번째 세그먼트 선택 시
setAnnotation(latitudeValue: 37.63207, longitudeValue: 127.0554, delta: 0.01, title: "인덕대학", subtitle: "노원구 월계동") // 인덕대학 주석 추가
self.lblLocationInfo1.text = "보고 계신 위치" // 레이블 1에 텍스트 설정
self.lblLocationInfo2.text = "한국폴리텍대학 강릉캠퍼스" // 레이블 2에 텍스트 설정
} else if sender.selectedSegmentIndex == 2 { // 세 번째 세그먼트 선택 시
setAnnotation(latitudeValue: 37.556876, longitudeValue: 126.914066, delta: 0.1, title: "이지스퍼블리싱", subtitle: "서울시 마포구 잔다리로 109 이지스 빌딩") // 이지스퍼블리싱 주석 추가
self.lblLocationInfo1.text = "보고 계신 위치" // 레이블 1에 텍스트 설정
self.lblLocationInfo2.text = "이지스퍼블리싱 출판사 " // 레이블 2에 텍스트 설정
}
}
}
출처:
Do it! 스위프트로 아이폰 앱 만들기 입문, 송호정, 이범근 저,이지스퍼블리싱, 2023년 01월 20일
---------------------------------------- 02 Hello World 앱 만들며 Xcode에 완벽 적응하기 03 원하는 이미지 화면에 출력하기 - 이미지 뷰 04 데이트 피커 사용해 날짜 선택하기 05 피커 뷰 사용해 원하는 항목 선택하기 06 얼럿 사용해 경고 표시하기 07 웹 뷰로 간단한 웹 브라우저 만들기 08 맵 뷰로 지도 나타내기 09 페이지 이동하기 - 페이지 컨트롤 10 탭 바 컨트롤러 이용해 여러 개의 뷰 넣기 11 내비게이션 컨트롤러 이용해 화면 전환하기 12 테이블 뷰 컨트롤러 이용해 할 일 목록 만들기 13 음악 재생하고 녹음하기 14 비디오 재생 앱 만들기 15 카메라와 포토 라이브러리에서 미디어 가져오기 16 코어 그래픽스로 화면에 그림 그리기 17 탭과 터치 사용해 스케치 앱 만들기 18 스와이프 제스처 사용하기 19 핀치 제스처 사용해 사진을 확대/축소하기
import UIKit // UIKit 프레임워크를 임포트하여 iOS 사용자 인터페이스를 구성할 수 있게 함
class ViewController: UIViewController { // ViewController라는 이름의 클래스를 정의하며, UIViewController를 상속받음
override func viewDidLoad() { // 뷰가 메모리에 로드된 후 호출되는 메서드를 오버라이드
super.viewDidLoad() // 부모 클래스의 viewDidLoad 메서드를 호출하여 기본 설정을 수행
// Do any additional setup after loading the view. // 뷰 로딩 후 추가적인 설정을 할 수 있는 부분 (현재는 비어 있음)
}
}
outlet변수 추가하는 방법
연결되어있는 거 끄기(연결이 중복돼 있는 경우) 경고 표시 있는 거 지우기
1. 기본 UILabel 생성 및 텍스트 설정
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// UILabel 생성
let myLabel = UILabel()
myLabel.text = "안녕하세요!" // 텍스트 설정
myLabel.textColor = .black // 텍스트 색상 설정
myLabel.font = UIFont.systemFont(ofSize: 24) // 글꼴 크기 설정
myLabel.textAlignment = .center // 텍스트 정렬 설정
// UILabel의 프레임 설정
myLabel.frame = CGRect(x: 50, y: 100, width: 300, height: 50)
// 뷰에 UILabel 추가
self.view.addSubview(myLabel)
}
}
2. UILabel을 IBOutlet으로 연결하여 텍스트 업데이트
import UIKit
class ViewController: UIViewController {
@IBOutlet weak var myLabel: UILabel! // 스토리보드에서 연결된 UILabel
override func viewDidLoad() {
super.viewDidLoad()
// UILabel의 텍스트 업데이트
myLabel.text = "안녕하세요, Swift!" // 텍스트 설정
}
}
<객체지향 언어인 Swift, Java, C#, JavaScript, Python에서 클래스를 생성하고 객체를 만드는 방법에 대해 각각 간단한 예제>
1. Swift
class Dog {
var name: String
init(name: String) {
self.name = name
}
func bark() {
print("\(name) says Woof!")
}
}
// 객체 생성
let myDog = Dog(name: "Buddy")
myDog.bark()
2. Java
class Dog {
String name;
Dog(String name) {
this.name = name;
}
void bark() {
System.out.println(name + " says Woof!");
}
}
// 객체 생성
public class Main {
public static void main(String[] args) {
Dog myDog = new Dog("Buddy");
myDog.bark();
}
}
3. C#
class Dog {
public string Name { get; set; }
public Dog(string name) {
Name = name;
}
public void Bark() {
Console.WriteLine($"{Name} says Woof!");
}
}
// 객체 생성
class Program {
static void Main() {
Dog myDog = new Dog("Buddy");
myDog.Bark();
}
}
4. JavaScript
class Dog {
constructor(name) {
this.name = name;
}
bark() {
console.log(`${this.name} says Woof!`);
}
}
// 객체 생성
const myDog = new Dog("Buddy");
myDog.bark();
5. Python
class Dog:
def __init__(self, name):
self.name = name
def bark(self):
print(f"{self.name} says Woof!")
# 객체 생성
my_dog = Dog("Buddy")
my_dog.bark()
-각 언어에서 클래스는 class 키워드를 사용하여 정의되고, 객체는 해당 클래스의 인스턴스를 생성하여 만듭니다. 각 예제에서 Dog 클래스를 만들고, name 속성을 통해 개의 이름을 설정한 후, bark 메서드를 호출하여 개가 짖는 모습을 출력합니다.
<각 객체지향 언어에서 상속을 구현하는 방법에 대해 간단한 예제>
1. Swift
class Animal {
func makeSound() {
print("Animal sound")
}
}
class Dog: Animal {
override func makeSound() {
print("Woof!")
}
}
// 객체 생성
let myDog = Dog()
myDog.makeSound() // 출력: Woof!
2. Java
class Animal {
void makeSound() {
System.out.println("Animal sound");
}
}
class Dog extends Animal {
@Override
void makeSound() {
System.out.println("Woof!");
}
}
// 객체 생성
public class Main {
public static void main(String[] args) {
Dog myDog = new Dog();
myDog.makeSound(); // 출력: Woof!
}
}
3. C#
class Animal {
public virtual void MakeSound() {
Console.WriteLine("Animal sound");
}
}
class Dog : Animal {
public override void MakeSound() {
Console.WriteLine("Woof!");
}
}
// 객체 생성
class Program {
static void Main() {
Dog myDog = new Dog();
myDog.MakeSound(); // 출력: Woof!
}
}
4. JavaScript
class Animal {
makeSound() {
console.log("Animal sound");
}
}
class Dog extends Animal {
makeSound() {
console.log("Woof!");
}
}
// 객체 생성
const myDog = new Dog();
myDog.makeSound(); // 출력: Woof!
5. Python
class Animal:
def make_sound(self):
print("Animal sound")
class Dog(Animal):
def make_sound(self):
print("Woof!")
# 객체 생성
my_dog = Dog()
my_dog.make_sound() # 출력: Woof!
위의 예제에서 각 언어는 Animal 클래스를 기본 클래스로 하고, Dog 클래스가 이를 상속받아 makeSound 또는 make_sound 메서드를 오버라이드하여 개의 소리를 출력하는 방법을 보여줍니다.
에러 원인: class 안에 있는 stored property는 반드시 초기값이 있어야한다
해결방법>
1.초기값 직접 지정하는 방법
var x : Int
class Man{
var age : Int = 0
var weight : Double = 0.0
}
2. 옵셔널로 만드는 방법(자동으로 nill 초기화됨)
var x : Int
class Man{
var age : Int? //nill로 초기화 되어 있는거임
var weight : Double?
}
인스턴스 만들고 메서드와 프로퍼티 접근
class Man{
var age : Int = 0
var weight : Double = 0.0
func display(){
print(age,weight)
}
}
var x : Int
var kim : Man = Man()//클래스명 다음의 괄호는 눈에 보이지 않는 defaultinitializer 나타냄
kim.age = 10
var Kim : Man = Man() //:Man은 생략 가능
var Kim = Man()
class Man{
var age : Int = 0
var weight : Double = 0.0
func display(){
print("나이: \(age), 몸무게: \(weight)")
}
}
var kim : Man = Man()//클래스명 다음의 괄호는 눈에 보이지 않는 defaultinitializer 나타냄
print(kim.age)
kim.age = 10
kim.weight = 20.5
print(kim.age,kim.weight)
kim.display()
<클래스(class or type) 메서드>
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 han : Man = Man()//클래스명 다음의 괄호는 눈에 보이지 않는 defaultinitializer 나타냄
print(han.age)
han.age = 10
han.weight = 20.5
print(han.age,han.weight)
han.display()//인스턴스 메서드는 인스턴스가 호출
Man.cM()//클래스 메서드는 클래스가 호출/class키워드로 만든 클래스메서드는 자식 클래스에서 override가능 함
Man.scM()//클래스 메서드는 클래스가 호출
*designated initializer
class Man{
var age : Int = 0
var weight : Double = 0.0
init(yourAge: Int, yourWeight : Double){
age = yourAge
weight = yourWeight
} //designated initializer
func display(){
print("나이:\(age), 몸무게:\(weight)")
}
}
var han : Man = Man.init(yourAge: 5, yourWeight:10.3)
print(han.age)
han.display()//인스턴스 메서드는 인스턴스가 호출
han.age = 10
han.weight = 20.5
han.display()
Swift에서 UI 이미지와 관련된 클래스를 사용하는 순서
UIImage: 기본 이미지 클래스로, 이미지 데이터를 저장하고 표시하는 데 사용됩니다.
UIImageView: 이미지를 화면에 표시하는 뷰 클래스입니다. UIImage를 포함하여 화면에 이미지를 보여줍니다.
UIImagePickerController: 사용자에게 사진 라이브러리나 카메라에서 이미지를 선택하게 하는 컨트롤러입니다.
CIImage: Core Image 프레임워크에서 이미지 처리를 위한 클래스입니다. 이미지 필터링 및 변환에 사용됩니다.
PHAsset: Photos 프레임워크에서 사진 및 비디오 자산을 나타내는 클래스입니다. 이미지 및 비디오의 메타데이터에 접근할 수 있습니다.
init 다음에 ?가 있으면 failable initializers
class Man{
var age : Int = 0
var weight : Double = 0.0
init?(age: Int, weight : Double){//? =>failable initializer쓰는 방법
if age <= 0 || weight <= 0.0 {
return nil
}else{
self.age = age
self.weight = weight
}
}
func display(){
print("나이:\(age), 몸무게 :\(weight)")
}
}
var han : Man? = Man(age: 5 ,weight: 10.3)//선언할때 옵셔널 man형으로 선언해야한다 (?,! 붙이기)
han!.display()
han!.age = 10
han!.weight = 20.5
1,2번 많이 씀
class Man{
var age : Int = 0
var weight : Double = 0.0
init?(age: Int, weight : Double){//? =>failable initializer쓰는 방법
if age <= 0 || weight <= 0.0 {
return nil
}else{
self.age = age
self.weight = weight
}
}
func display(){
print("나이:\(age), 몸무게 :\(weight)")
}
}
var han : Man? = Man(age: 0 ,weight: 10.3)
if let han{// 옵셔널 풀린 han
han.display()
}//좋은 방법
-옵셔널 선언하고~ 풀어주는 방법
class Man{
var age : Int = 0
var weight : Double = 0.0
init?(age: Int, weight : Double){//? =>failable initializer쓰는 방법
if age <= 0 || weight <= 0.0 {
return nil
}else{
self.age = age
self.weight = weight
}
}
func display(){
print("나이:\(age), 몸무게 :\(weight)")
}
}
if let han = Man(age: 0 ,weight: 10.3){
han.display()
}
class Man {
var age: Int // 나이를 저장할 변수
var weight: Double // 몸무게를 저장할 변수
// 나이와 몸무게를 출력하는 메서드
func display() {
print("나이=\(age), 몸무게=\(weight)")
}
// 초기화 메서드, 나이가 0 이하일 경우 nil 반환
init?(age: Int, weight: Double) {
if age <= 0 {
return nil // 나이가 0 이하이면 nil을 반환하여 인스턴스 생성을 실패시킴
} else {
self.age = age // 나이가 유효하면 초기화
}
self.weight = weight // 몸무게 초기화
}
}
// 1-1. 옵셔널 형으로 선언하여 kim 변수 생성
var kim: Man? = Man(age: 1, weight: 3.5)
// 1-2. 옵셔널 바인딩을 사용하여 kim의 값을 안전하게 언래핑
if let kim1 = kim {
kim1.display() // kim1이 nil이 아닐 경우 display 메서드 호출
}
// 2. 인스턴스 생성과 동시에 옵셔널 바인딩
if let kim2 = Man(age: 2, weight: 5.5) {
kim2.display() // kim2가 nil이 아닐 경우 display 메서드 호출
}
// 3. 인스턴스 생성하면서 바로 강제 언래핑
var kim3: Man = Man(age: 3, weight: 7.5)! // Man 인스턴스가 nil이 아님을 확신하고 강제 언래핑
kim3.display() // kim3의 display 메서드 호출
// 4. 옵셔널 인스턴스를 사용시 강제 언래핑
var kim4: Man? = Man(age: 4, weight: 10.5) // 옵셔널 형으로 kim4 생성
kim4!.display() // kim4가 nil이 아님을 확신하고 강제 언래핑하여 display 메서드 호출
상속, 오버라이딩 , failable initializers 이 포함이 된 간단한 소스 예제
// 기본 클래스
class Animal {
var name: String // 동물의 이름
// failable initializer: 이름이 비어있으면 nil 반환
init?(name: String) {
if name.isEmpty {
return nil // 이름이 비어있으면 초기화 실패
}
self.name = name // 이름 초기화
}
// 기본 동물 소리 메서드
func makeSound() {
print("동물이 소리를 냅니다.")
}
}
// 서브 클래스
class Dog: Animal {
// 오버라이드: Dog 클래스의 소리 메서드
override func makeSound() {
print("\(name)는 멍멍하고 짖습니다.") // Dog의 소리
}
}
// 사용 예시
// 1. failable initializer 사용 예
if let myDog = Dog(name: "Buddy") { // 초기화 성공
myDog.makeSound() // 출력: Buddy는 멍멍하고 짖습니다.
} else {
print("이름이 비어 있습니다.")
}
// 2. failable initializer 실패 예
if let myCat = Animal(name: "") { // 초기화 실패
myCat.makeSound()
} else {
print("이름이 비어 있습니다.") // 출력: 이름이 비어 있습니다.
}
else절 내의 코드는 현재 코드 흐름을 빠져나갈 수 있는 구문(return, break, continue, throw 등)을 포함해야 하며, 다른 함수를 호출할 수도 있음.
기본 구조
guard <불리언 표현식> else {
// 거짓일 경우 실행될 코드
<코드 블록을 빠져 나갈 구문>
}
// 참일 경우 실행되는 코드는 이곳에 위치
조기 출구(early exit): 특정 조건에 맞지 않을 경우 현재의 함수나 반복문에서 빠져나가는 전략을 제공.
Guard~let 활용
사용 범위:return,break,continue,throw등이 가능한 상황에서 사용 가능.
가독성: 옵셔널 바인딩을 통해 다중if~else를 피하고, 코드 가독성을 높임.
함수 외부에서의 사용:guard let으로 언래핑된 변수는guard문 밖에서도 사용할 수 있음. 반면,if문으로 언래핑된 변수는 그 안에서만 사용 가능.
guard~let의 활용
var x = 1
while true {
guard x < 5 else { break }
print(x)
x = x + 1
}
조건식이 거짓일 때:guard문이 실행되어else블록의 코드가 수행되고, 지정된 제어문으로 빠져나감.
조건식이 참일 때: 이후 코드가 정상적으로 실행됨.
guard let~else로 옵셔널 바인딩
func multiplyByTen(value: Int?) {
guard let number = value else {//조건식이 거짓(nil)일 때 else 블록 실행
print("nil")
return
}
print(number*10) //조건식이 참일 때 실행, 주의 : number를 guard문 밖인 여기서도 사용 가능
}
multiplyByTen(value: 3) //30
multiplyByTen(value: nil)//nil
multiplyByTen(value: 10)//100
if~let vs. guard~let
func printName(firstName:String, lastName:String?){
// if let
if let lName = lastName { // lastName이 nil이 아니면
print(lName,firstName)
}
else{print("성이 없네요!")
}
// guard let
//guard let lName= lastName else { // lastName이 nil이면
//print("성이 없네요!")
//return // early exit
//}
//print(lName,firstName)
}
printName(firstName:"길동", lastName:"홍")//홍 길동
printName(firstName: "길동", lastName:nil)//성이 없네요!
디폴트 매개변수(아규먼트) 정의하기
func sayHello(count: Int, name: String = "길동") -> String {
return ("\(name), 너의 번호는 \(count)")
}
var message = sayHello(count: 10, name: "소프트")
// 결과: "소프트, 너의 번호는 10"
message = sayHello(count: 100)
print(message) // 결과: "길동, 너의 번호는 100"
import Foundation
func sss(x: Int, y: Int) -> (sum: Int, sub: Int, mul: Int, div: Double, mod: Int) {
let sum = x + y
let sub = x - y
let mul = x * y
let div = Double(x) / Double(y) // 같은 자료형만 연산 가능
let mod = x % y // 나머지 연산
return (sum, sub, mul, div, mod)
}
var result = sss(x: 10, y: 3)
print(result.sum) // 13
print(result.sub) // 7
print(result.mul) // 30
print(result.div) // 3.33333333333333
print(result.mod) // 1
// 소수점 3자리로 출력
String(format: "%.3f", result.div)////string은 구조체라서 import Foundation써야함
// 3.333
// 함수의 자료형 출력
print(type(of: sss)) // (Int, Int) -> (sum: Int, sub: Int, mul: Int, div: Double, mod: Int)
가변 매개변수(variadic parameter)
func displayStrings(strings: String...) //string... =>string이 몇개가 와도 관계가 없다
{
for string in strings {
print(string)
}
}
displayStrings(strings: "일", "이", "삼", "사")
displayStrings(strings: "one", "two")
displayStrings(strings: "one", "two","a","b","c")
과제 : 가변 매개변수(variadic parameter) 임의의 개수의 정수 값의 합을 출력하는 함수를 작성하여 호출
func add(numbers:Int...){
var sum:Int=0
for num in numbers{
sum += num
}
print(sum)
}
add(numbers:1,2,3) //6
add(numbers:2,2,2,2,2) //10
add(numbers:1,1,1,1,1,1,1,1,1,1) //10
add(numbers:1,1,1,1) //4
Swift 3에서는 inout의 위치가 바뀜( call by address하고 싶은 매개변수의 자료형 앞에 inout 씀)
var myValue = 10
func doubleValue (value: inout Int) -> Int {
value += value
return(value)
}
print(myValue)//10
print(doubleValue(value : &myValue)) //20
print(myValue)//20
Swift 문자열 서식(swift string format 자리수)
import Foundation
let weight = 60.0
let height = 170.0
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 = "저체중"
}
print("BMI:\(shortenedBmi), 판정:\(body)")
함수 : 일급 객체 실습
// num에 1을 더하는 함수
func up(num: Int) -> Int {
return num + 1
}
// num에서 1을 빼는 함수
func down(num: Int) -> Int {
return num - 1
}
// up 함수를 toUp 변수에 할당
let toUp = up
// up 함수 호출
print(up(num: 10)) // 결과: 11
// toUp 변수 호출
print(toUp(10)) // 결과: 11
// down 함수를 toDown 변수에 할당
let toDown = down
// 함수 타입을 매개변수로 받아 결과를 출력하는 함수
func upDown(Fun: (Int) -> Int, value: Int) {
let result = Fun(value)
print("결과 = \(result)")
}
// toUp(10) 호출
upDown(Fun: toUp, value: 10) // 결과: 결과 = 11
// toDown(10) 호출
upDown(Fun: toDown, value: 10) // 결과: 결과 = 9
// Bool 값을 기반으로 함수를 결정하여 반환하는 함수
func decideFun(x: Bool) -> (Int) -> Int {
if x {
return toUp // true일 경우 toUp 반환
} else {
return toDown // false일 경우 toDown 반환
}
}
// decideFun 호출하여 true일 경우 toUp을 반환
let r = decideFun(x: true) // let r = toUp
print(type(of: r)) // 결과: (Int) -> Int
// r(10) 호출
print(r(10)) // 결과: 11 (toUp(10) 호출)
first class object : (1)함수를 변수에 저장 가능
// 인치를 피트로 변환하는 함수
func inchesToFeet(inches: Float) -> Float {
return inches * 0.0833333 // 1인치는 약 0.0833 피트
}
// inchesToFeet 함수를 toFeet 변수에 할당하여 함수처럼 사용
let toFeet = inchesToFeet
// toFeet 함수를 사용하여 인치 값을 피트로 변환
let result = toFeet(10) // 10 인치를 피트로 변환
print(result) // 결과 출력
클로저 표현식
// 두 정수를 더하는 함수
func add(x: Int, y: Int) -> Int {
return (x + y)
}
print(add(x: 10, y: 20)) // 결과: 30
print(type(of:add))
// 클로저 정의
let add1 = { (x: Int, y: Int) -> Int in
return (x + y) // 중괄호가 필요
}
print(add1(10, 20)) // 결과: 30
print(type(of:add1))
#include <iostream>
using namespace std;
class Person {
public:
string name;
int age;
Person(string n, int a) : name(n), age(a) {}
};
int main() {
Person person("홍길동", 30);
cout << person.name << "의 나이는 " << person.age << "세입니다." << endl;
return 0;
}
Java
class Person {
String name;
int age;
Person(String n, int a) {
name = n;
age = a;
}
}
public class Main {
public static void main(String[] args) {
Person person = new Person("홍길동", 30);
System.out.println(person.name + "의 나이는 " + person.age + "세입니다.");
}
}
Python
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
person = Person("홍길동", 30)
print(f"{person.name}의 나이는 {person.age}세입니다.")
JavaScript
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
}
const person = new Person('홍길동', 30);
console.log(`${person.name}의 나이는 ${person.age}세입니다.`);
xcode 정렬: ctrl+i
1~9출력
for i in 0..<10 {
print(i)
}
for i in 0...9 {
print(i)
}
이름 9번 출력
for _ in 0...9 {//= 0; i < 10; i+=1 {
print("kdh")
}
// 0부터 9까지 반복
for i in 0...9 {
// i에 1을 더한 값을 출력하고 "kdh"라는 문자열을 붙임
print("\(i + 1): kdh")
}
xcode 주석: commend +/
<배열의 항목 접근>
// 문자열 배열을 정의
let names = ["A", "B", "C", "D"]
// 배열의 인덱스 1부터 끝까지 반복
for name in names[1...] {
// 현재 이름을 출력
print(name)
}
<if문>
// 변수 x를 10으로 초기화
var x = 10
// x가 5보다 큰지 확인
if x > 5 {
// 조건이 참일 경우 메시지를 출력
print("5보다 큽니다")
}
swift제어문 예시
1. 조건문
if문
let number = 10
if number > 5 {
print("5보다 큽니다") // 조건이 참일 때 실행
}
if-else문
let number = 3
if number > 5 {
print("5보다 큽니다")
} else {
print("5보다 작거나 같습니다") // 조건이 거짓일 때 실행
}
switch문
let fruit = "사과"
switch fruit {
case "바나나":
print("바나나입니다.")
case "사과":
print("사과입니다.") // 해당하는 케이스 실행
default:
print("다른 과일입니다.")
}
2. 반복문
for문
for i in 1...5 { // 1부터 5까지 반복
print(i) // 1, 2, 3, 4, 5 출력
}
while문
var count = 0
while count < 3 {
print("Count는 \(count)") // Count는 0, 1, 2 출력
count += 1
}
repeat-while문
var count = 0
repeat {
print("Count는 \(count)") // Count는 0, 1, 2 출력
count += 1
} while count < 3
3. 제어 흐름 변경
break문
for i in 1...5 {
if i == 3 {
break // i가 3이면 반복문 종료
}
print(i) // 1, 2 출력
}
continue문
for i in 1...5 {
if i == 3 {
continue // i가 3이면 다음 반복으로 넘어감
}
print(i) // 1, 2, 4, 5 출력
}
optional
(implicitly unwrapped)
var x : Int = 10
print(x)//10
var y : Int? = 20 //optional 변수 (자료형 뒤에 ?)
print(y!)//20 //optional 변수의 값을 저장할 경우 변수 뒤에 !해야됨/ 안하면 => 출력값: Optional(20)
nil(값이 없다)
var y : Int? // 초기값 없앰
print(y)//nil(값이 없다)
// 변수 x를 Int 타입으로 선언하고 10으로 초기화
var x: Int = 10
print(x) // x의 값을 출력: 10
// 변수 y를 Int? (옵셔널) 타입으로 선언하고 20으로 초기화
var y: Int? = 20
// y의 값을 강제로 언래핑하여 1을 더한 후 다시 y에 할당
y = y! + 1 // y의 값이 nil이 아닐 때만 안전하게 언래핑 가능
print(y) // y의 값을 출력: 21
<optional binding(여러 옵셔널 값 동시에 언래핑)>
var x : Int?
//x = 10
if x != nil {
print(x!)
}
else {
print("nil")//nil
}
var x : Int?
x = 10
if let x {
print(x)//10
}
var x : Int? = 10
var y : Int! = 20
var z : Int = 1
print(x,y,z)
z = x!
print(z)
z = y!
print(z)
if let x, let y {
print(x,y)
}
사용자가 사용하는 것 같지 않으면 자동으로 풀어버림
var x : Int? = 10
var y : Int! = 20
var z : Int = 1
print(x,y,z)
z = x! + 1
print(z)
z = y + 1
print(z)
if let x, let y {
print(x,y)
}
var x : Int? //= 10
var y : Int = 0
y = x ?? 1
print(x,y)//nil 1
swift에서 optional 푸는 방법을 많이 사용하는 순서
1. 강제 언래핑 (Force Unwrapping)
! 연산자를 사용하여 옵셔널 값을 강제로 언래핑합니다. 주의: 값이 nil일 경우 런타임 오류가 발생합니다
let optionalValue: Int? = 10
let value = optionalValue! // 강제 언래핑
2. 옵셔널 바인딩 (Optional Binding)
if let 또는 guard let을 사용하여 옵셔널 값을 안전하게 언래핑합니다. 값이 nil이 아닐 경우에만 실행됩니다.
if let unwrappedValue = optionalValue {
print(unwrappedValue) // 값이 있을 경우 실행
}
------
guard let unwrappedValue = optionalValue else {
return // 값이 nil일 경우 함수 종료
}
print(unwrappedValue)
3. nil 병합 연산자 (Nil Coalescing Operator)
?? 연산자를 사용하여 옵셔널 값이 nil일 경우 기본 값을 제공합니다.
let value = optionalValue ?? 0 // optionalValue가 nil이면 0을 사용
4. 옵셔널 체이닝 (Optional Chaining)
옵셔널 값의 속성이나 메소드를 호출할 때 사용합니다. 값이 nil이면 호출이 무시됩니다.
let length = optionalValue?.description.count // nil이면 length도 nil이 됨
5. 옵셔널 배열 (Optional Array)
배열의 요소로 옵셔널을 사용하고, compactMap을 이용하여 nil이 아닌 값만 필터링할 수 있습니다.
let optionalArray: [Int?] = [1, nil, 2, nil, 3]
let values = optionalArray.compactMap { $0 } // [1, 2, 3]