SA성아 2024. 11. 13. 16:46

출처:

----------------------------------------
02 Hello World 앱 만들며 Xcode에 완벽 적응하기
03 원하는 이미지 화면에 출력하기 - 이미지 뷰
04 데이트 피커 사용해 날짜 선택하기
05 피커 뷰 사용해 원하는 항목 선택하기
06 얼럿 사용해 경고 표시하기
07 웹 뷰로 간단한 웹 브라우저 만들기
08 맵 뷰로 지도 나타내기
09 페이지 이동하기 - 페이지 컨트롤
10 탭 바 컨트롤러 이용해 여러 개의 뷰 넣기
11 내비게이션 컨트롤러 이용해 화면 전환하기
12 테이블 뷰 컨트롤러 이용해 할 일 목록 만들기
13 음악 재생하고 녹음하기
14 비디오 재생 앱 만들기
15 카메라와 포토 라이브러리에서 미디어 가져오기
16 코어 그래픽스로 화면에 그림 그리기
17 탭과 터치 사용해 스케치 앱 만들기
18 스와이프 제스처 사용하기
19 핀치 제스처 사용해 사진을 확대/축소하기

 

--------------------------------------------------------------------------------------

09

// UIKit 프레임워크를 불러옵니다. UI 요소를 사용하기 위해 필요합니다.
import UIKit

// 이미지 파일 이름을 저장하는 배열을 정의합니다.
var images = [ "01.png", "02.png", "03.png", "04.png", "05.png", "06.png" ]

// ViewController 클래스는 UIViewController를 상속합니다.
class ViewController: UIViewController {
    // UIImageView와 UIPageControl 아웃렛을 연결합니다.
    @IBOutlet var imgView: UIImageView!
    @IBOutlet var pageControl: UIPageControl!
    
    // viewDidLoad 메서드는 뷰가 로드될 때 호출됩니다.
    override func viewDidLoad() {
        super.viewDidLoad()
        // 추가적인 설정을 여기서 수행합니다.
        
        // 페이지 컨트롤의 페이지 수를 이미지 배열의 개수로 설정합니다.
        pageControl.numberOfPages = images.count
        // 초기 현재 페이지를 3으로 설정합니다.
        pageControl.currentPage = 3
        
        // 페이지 인디케이터의 색상을 흰색으로 설정합니다.
        pageControl.pageIndicatorTintColor = UIColor.white
        // 현재 페이지 인디케이터의 색상을 파란색으로 설정합니다.
        pageControl.currentPageIndicatorTintColor = UIColor.blue
        
        // 이미지 뷰의 초기 이미지를 이미지 배열의 첫 번째 이미지로 설정합니다.
        imgView.image = UIImage(named: images[0])
    }

    // pageControl의 값이 변경될 때 호출되는 액션 메서드입니다.
    @IBAction func pageChange(_ sender: UIPageControl) {
        // 현재 페이지에 해당하는 이미지를 이미지 뷰에 표시합니다.
        imgView.image = UIImage(named: images[pageControl.currentPage])
    }
    
}

 

 

10. 탭 바 컨트롤러

화면 밑에 탭으로 여러개의 화면으로 빨리 진행할 수 있도록 하는 컨트롤러이다.

 

11.

네비게이션 컨트롤러

 

12

// UIKit 프레임워크를 불러옵니다.
import UIKit

// 테이블에 표시할 항목과 해당 이미지 파일 이름을 저장하는 배열을 정의합니다.
var items = ["책 구매", "철수와 약속", "스터디 준비하기"]
var itemsImageFile = ["cart.png", "clock.png", "pencil.png"]

// TableViewController 클래스는 UITableViewController를 상속받아 테이블 뷰를 관리합니다.
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) {
        tvListView.reloadData()
    }

    // MARK: - Table view data source

    // 섹션 수를 반환합니다. 섹션은 1개로 설정되어 있습니다.
    override func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }

    // 각 섹션의 행 수를 반환합니다. items 배열의 개수를 반환하여 행 수를 설정합니다.
    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 func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
        return true
    }
    */

    // 테이블 뷰에서 삭제 기능을 지원합니다.
    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 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 func tableView(_ tableView: UITableView, canMoveRowAt indexPath: IndexPath) -> Bool {
        return true
    }
    */

    // MARK: - Navigation

    // 세그웨이를 사용하여 화면을 전환하기 전에 준비 작업을 합니다.
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        // 세그웨이 식별자가 "sgDetail"일 때 실행됩니다.
        if segue.identifier == "sgDetail" {
            // 전환될 셀을 가져와 해당 셀의 인덱스를 구합니다.
            let cell = sender as! UITableViewCell
            let indexPath = self.tvListView.indexPath(for: cell)
            // 세그웨이의 목적지 뷰 컨트롤러를 DetailViewController로 캐스팅합니다.
            let detailView = segue.destination as! DetailViewController
            // 선택된 항목의 텍스트를 DetailViewController로 전달합니다.
            detailView.reciveItem(items[((indexPath! as NSIndexPath).row)])
        }
    }
    
}

 

컨트롤러: 기능적인 부분

Q: iOS앱을 만들때 가장 많이 사용하는 컨트롤러

A: iOS 앱 개발에서 가장 많이 사용하는 컨트롤러는 UIViewController UITableViewController입니다.

  • UIViewController: 모든 화면의 기본이 되는 컨트롤러로, 화면을 관리하고 여러 UI 요소를 배치하는 데 사용됩니다. UIViewController를 통해 다양한 화면 전환 방식과 함께 사용자 인터페이스를 구성할 수 있습니다.
  • UITableViewController: 리스트 형태로 데이터를 보여줄 때 주로 사용됩니다. 메시지 목록, 설정 화면 등 다양한 형태의 리스트를 손쉽게 구현할 수 있고, 셀을 편집, 삭제, 이동하는 등의 기능도 쉽게 추가할 수 있습니다.

이외에도 UICollectionViewController, UINavigationController, UITabBarController 등도 많이 사용되는 컨트롤러입니다.

 

13

//
//  ViewController.swift
//  Audio
//
//  Created by BeomGeun Lee on 2021.
//

// UIKit과 AVFoundation 프레임워크를 불러옵니다.
import UIKit
import AVFoundation

// ViewController 클래스는 UIViewController를 상속받고, AVAudioPlayerDelegate와 AVAudioRecorderDelegate를 채택하여 오디오 재생 및 녹음을 관리합니다.
class ViewController: UIViewController, AVAudioPlayerDelegate, AVAudioRecorderDelegate {
    
    // 오디오 플레이어와 파일 URL 변수 선언
    var audioPlayer : AVAudioPlayer!
    var audioFile : 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!
    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)
        } 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)")
        }
        do {
            try session.setActive(true)
        } catch let error as NSError {
            print("Error-setActive : \(error)")
        }
    }
    
    // 재생 초기 설정 함수
    func initPlay() {
        do {
            audioPlayer = try AVAudioPlayer(contentsOf: audioFile)
        } 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
    }
    
    // TimeInterval 값을 문자열로 변환하는 함수 (분:초 형식)
    func convertNSTimeInterval2String(_ time: TimeInterval) -> String {
        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 {
            initRecord()
        }
    }
    
    // 녹음 버튼 눌렀을 때 호출되는 함수
    @IBAction func btnRecord(_ sender: UIButton) {
        if (sender as AnyObject).titleLabel?.text == "Record" {
            audioRecorder.record()
            (sender as AnyObject).setTitle("Stop", for: UIControl.State())
            progressTimer = Timer.scheduledTimer(timeInterval: 0.1, target: self, selector: timeRecordSelector, userInfo: nil, repeats: true)
        } else {
            audioRecorder.stop()
            progressTimer.invalidate()
            (sender as AnyObject).setTitle("Record", for: UIControl.State())
            btnPlay.isEnabled = true
            initPlay()
        }
    }
    
    // 녹음 시간 업데이트 함수
    @objc func updateRecordTime() {
        lblRecordTime.text = convertNSTimeInterval2String(audioRecorder.currentTime)
    }
}

 

14

//
//  ViewController.swift
//  MoviePlayer
//
//  Created by Ho-Jeong Song on 2021/11/26.
//

// UIKit과 AVKit 프레임워크를 불러옵니다.
import UIKit
import AVKit

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

    // 뷰가 로드될 때 실행되는 함수
    override func viewDidLoad() {
        super.viewDidLoad()
        // 초기 설정을 여기서 할 수 있습니다.
    }

    // 내부 파일 재생 버튼이 눌렸을 때 실행되는 함수
    @IBAction func btnPlayInternalMovie(_ sender: UIButton) {
        // 앱 번들에 포함된 "FastTyping.mp4" 파일 경로를 가져옴
        let filePath: String? = Bundle.main.path(forResource: "FastTyping", ofType: "mp4")
        
        // 파일 경로를 NSURL로 변환
        let url = NSURL(fileURLWithPath: filePath!)
        
        // 비디오 재생 함수 호출
        playVideo(url: url)
    }
    
    // 외부 파일 재생 버튼이 눌렸을 때 실행되는 함수
    @IBAction func btnPlayerExternalMovie(_ sender: UIButton) {
        // 외부 URL의 비디오 파일 주소 설정
        let url = NSURL(string: "https://dl.dropboxusercontent.com/s/e38auz050w2mvud/Fireworks.mp4")!
        
        // 비디오 재생 함수 호출
        playVideo(url: url)
    }
    
    // 비디오 재생 기능을 담당하는 함수
    private func playVideo(url: NSURL)  {
        // AVPlayerViewController 인스턴스 생성
        let playerController = AVPlayerViewController()
        
        // AVPlayer 인스턴스 생성하여 url을 할당
        let player = AVPlayer(url: url as URL)
        
        // AVPlayerViewController의 player에 AVPlayer 설정
        playerController.player = player
        
        // 현재 뷰 컨트롤러에서 AVPlayerViewController를 모달로 띄우고, 재생 시작
        self.present(playerController, animated: true) {
            player.play()
        }
    }
}

 

15

 

16

 

 

17

//
//  ViewController.swift
//  Sketch
//
//  Created by Ho-Jeong Song on 2021/12/01.
//

import UIKit

class ViewController: UIViewController {
    @IBOutlet var imgView: UIImageView!  // 그림을 그릴 UIImageView
    @IBOutlet var txtLineSize: UITextField!  // 선의 두께를 입력할 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
    }
    
    // 사용자가 화면을 터치했을 때 호출되는 함수
    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에 설정
        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
    }
    
    // 새로운 기능: 선택된 색상을 텍스트로 표시하는 기능 추가
    @IBOutlet var lblColorDisplay: UILabel!  // 선택된 색상을 표시할 UILabel
    
    func updateColorDisplay() {
        switch lineColor {
        case UIColor.black.cgColor:
            lblColorDisplay.text = "Black"
        case UIColor.red.cgColor:
            lblColorDisplay.text = "Red"
        case UIColor.green.cgColor:
            lblColorDisplay.text = "Green"
        case UIColor.blue.cgColor:
            lblColorDisplay.text = "Blue"
        default:
            lblColorDisplay.text = "Custom Color"
        }
    }
    
    // 색상 버튼들이 눌릴 때마다 선택된 색상을 표시하도록 설정
    @IBAction func btnChangeLineColorBlackWithLabel(_ sender: UIButton) {
        lineColor = UIColor.black.cgColor
        updateColorDisplay()
    }
    
    @IBAction func btnChangeLineColorRedWithLabel(_ sender: UIButton) {
        lineColor = UIColor.red.cgColor
        updateColorDisplay()
    }
    
    @IBAction func btnChangeLineColorGreenWithLabel(_ sender: UIButton) {
        lineColor = UIColor.green.cgColor
        updateColorDisplay()
    }
    
    @IBAction func btnChangeLineColorBlueWithLabel(_ sender: UIButton) {
        lineColor = UIColor.blue.cgColor
        updateColorDisplay()
    }
}

 

18

19

 

--------------------------------------------------------------------------------------------

BMI 앱 만들기

https://apps.apple.com/us/app/bmi-calculator-weight-loss/id666822519?platform=iphone&see-all=customers-also-bought-apps

 

클래스의 프로퍼티 선언에 IBOutlet와 IBInspectable 사용 

클래스의 메서드 선언에 IBAction과 IBSegueAction 사용

이미지는 Assets.xcassets에 넣음

 

숫자만 나옴