iOS프로그래밍 실무 3주차

post-thumbnail

출처 : smileHan - iOS 프로그래밍기초

GPT : 무드등 iOS앱을 만드려고해 앱스토어에서 인기있는 앱들을 참고하여 사전계획서를 작성해줘

앱 개요

무드등 앱은 사용자가 다양한 색상과 밝기를 조절하여 원하는 분위기를 연출할 수 있도록 돕는 앱입니다. 사용자는 자신의 기분이나 상황에 맞게 조명을 설정할 수 있으며, 추가적인 기능으로 타이머, 알람, 음악 재생 등을 제공할 수 있습니다.

주요 기능

  • 색상 조절: 다양한 색상 옵션을 제공하여 사용자가 원하는 분위기를 쉽게 설정할 수 있도록 합니다. 예를 들어, 부드러운 파스텔 색상부터 강렬한 원색까지 선택할 수 있습니다.

  • 밝기 조절: 화면 밝기를 조정할 수 있는 기능을 추가하여, 사용자가 원하는 밝기를 설정할 수 있도록 합니다.

  • 타이머 및 알람: 사용자가 설정한 시간에 자동으로 조명이 켜지거나 꺼지도록 하는 기능을 추가합니다.

  • 음악 재생: 사용자가 선택한 음악을 배경으로 재생할 수 있는 기능을 제공하여, 더욱 몰입감 있는 경험을 제공합니다.

  • 디자인 및 사용자 경험 직관적인 UI: 사용자가 쉽게 조작할 수 있도록 직관적인 인터페이스를 설계합니다. 슬라이더를 통해 색상과 밝기를 조절할 수 있도록 하며, 미리보기 기능을 추가하여 사용자가 선택한 색상을 즉시 확인할 수 있도록 합니다.

  • 테마 및 배경: 다양한 테마를 제공하여 사용자가 자신의 취향에 맞게 앱을 꾸밀 수 있도록 합니다.
    예를 들어, 자연, 도시, 우주 등의 테마를 제공할 수 있습니다.

마케팅 전략

  • 소셜 미디어 활용: 인스타그램, 페이스북 등 소셜 미디어 플랫폼을 통해 앱의 기능과 사용 사례를 홍보합니다.

  • 사용자들이 자신의 무드등 설정을 공유할 수 있는 캠페인을 진행합니다.

  • 리뷰 및 피드백: 초기 사용자들로부터 피드백을 받아 앱을 개선하고, 긍정적인 리뷰를 통해 신뢰성을 높입니다.

결론

  • 무드등 iOS 앱은 사용자가 원하는 분위기를 쉽게 조절할 수 있는 다양한 기능을 제공하여, 일상 속에서 편안함과 즐거움을 느낄 수 있도록 돕습니다.
  • 이 앱은 직관적인 디자인과 사용자 경험을 통해 많은 사용자들에게 사랑받을 수 있을 것입니다.
  • 이 계획서를 바탕으로 앱 개발을 진행하면, 성공적인 무드등 앱을 만들 수 있을 것입니다.

GPT : 스토리보드 기반으로 소스코드를 작성해줘

import UIKit
import AVFoundation

class ViewController: UIViewController {
    
    @IBOutlet weak var colorView: UIView!
    @IBOutlet weak var brightnessSlider: UISlider!
    @IBOutlet weak var timerLabel: UILabel!
    @IBOutlet weak var playMusicButton: UIButton!
    
    var timer: Timer?
    var remainingTime: Int = 0
    var audioPlayer: AVAudioPlayer?
    
    override func viewDidLoad() {
        super.viewDidLoad()
        setupUI()
    }
    
    func setupUI() {
        colorView.layer.cornerRadius = 20
        colorView.backgroundColor = .white
        brightnessSlider.value = 1.0
        timerLabel.text = "타이머 없음"
    }
    
    @IBAction func changeColor(_ sender: Any) {
        let picker = UIColorPickerViewController()
        picker.delegate = self
        present(picker, animated: true)
    }
    
    @IBAction func changeBrightness(_ sender: UISlider) {
        colorView.alpha = CGFloat(sender.value)
    }
    
    @IBAction func setTimer(_ sender: Any) {
        let alert = UIAlertController(title: "타이머 설정", message: "몇 분 후에 종료할까요?", preferredStyle: .alert)
        alert.addTextField { textField in
            textField.keyboardType = .numberPad
        }
        alert.addAction(UIAlertAction(title: "설정", style: .default, handler: { [weak self] _ in
            if let text = alert.textFields?.first?.text, let minutes = Int(text) {
                self?.startTimer(minutes: minutes)
            }
        }))
        alert.addAction(UIAlertAction(title: "취소", style: .cancel))
        present(alert, animated: true)
    }
    
    func startTimer(minutes: Int) {
        remainingTime = minutes * 60
        timerLabel.text = "남은 시간: \(minutes)분"
        
        timer?.invalidate()
        timer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { [weak self] _ in
            guard let self = self else { return }
            if self.remainingTime > 0 {
                self.remainingTime -= 1
                self.timerLabel.text = "남은 시간: \(self.remainingTime / 60)\(self.remainingTime % 60)초"
            } else {
                self.timer?.invalidate()
                self.colorView.backgroundColor = .black
                self.timerLabel.text = "타이머 종료"
            }
        }
    }
    
    @IBAction func playMusic(_ sender: UIButton) {
        if let path = Bundle.main.path(forResource: "background_music", ofType: "mp3") {
            let url = URL(fileURLWithPath: path)
            do {
                audioPlayer = try AVAudioPlayer(contentsOf: url)
                audioPlayer?.play()
            } catch {
                print("음악 재생 오류: \(error.localizedDescription)")
            }
        }
    }
}

extension ViewController: UIColorPickerViewControllerDelegate {
    func colorPickerViewControllerDidSelectColor(_ viewController: UIColorPickerViewController) {
        colorView.backgroundColor = viewController.selectedColor
    }
}

Minimum Deployment

  • 호환 버전을 지정
    16.0 버전까지 이용 가능

Bundle Identifier

  • 앱의 고유한 번호
    앱끼리는 서로 번호가 중복될 수 없다.

Deployment Info

  • 화면 회전 시 같이 돌아하는 동작의 옵션

라이프사이클

  • 앱의 실행 과정에서 발생하는 이벤트의 흐름
  • 따로 메서드의 호출을 하지 않았지만 자동으로 print문이 출력되는것을 확인 할 수있습니다.
  • 출력순서 [viewDidLoad] -> [viewWillAppear] -> [viewDidAppear]
  • 자세한건 아래 참조

상세 설명

import UIKit  // UIKit 프레임워크를 임포트하여 UI 관련 기능을 사용할 수 있도록 함

// ViewController 클래스 정의 (UIViewController를 상속받음)
class ViewController: UIViewController {

    // ✅ viewDidLoad: 뷰가 메모리에 로드될 때 한 번만 실행됨
    override func viewDidLoad() {
        super.viewDidLoad() // 부모 클래스의 viewDidLoad() 실행 (필수)
        print("viewDidLoad") // 콘솔에 "viewDidLoad" 출력 (뷰가 처음 로드될 때 확인용)
    }
    
    // 🟡 viewWillAppear: 화면이 나타나기 직전에 호출됨 (화면이 갱신될 때마다 실행)
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated) // 부모 클래스의 viewWillAppear 실행 (필수)
        print("viewWillAppear") // 콘솔에 "viewWillAppear" 출력 (화면이 나타나기 전 확인용)
    }
    
    // 🟢 viewDidAppear: 화면이 완전히 나타난 후 호출됨
    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated) // 부모 클래스의 viewDidAppear 실행 (필수)
        print("viewDidAppear") // 콘솔에 "viewDidAppear" 출력 (화면이 나타난 후 확인용)
    }
}

View Life Cycle

  • ViewDidLoad : (주의!) 앱이 한번 켜졌을때 1번만 실행된다.
  • 아래와 같은 Life Cycle을 가지고있기 때문에 메서드의 Life Cycle생각하며 개발해야 합니다.

AppDelegate.swift

import UIKit  // UIKit 프레임워크를 가져와 UI 관련 기능을 사용

@main
class AppDelegate: UIResponder, UIApplicationDelegate {

    // 앱이 실행될 때 최초로 호출되는 메서드
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        // 앱이 실행된 후 초기 설정을 수행할 수 있는 지점
        // 예: Firebase 초기화, 푸시 알림 설정, 초기 데이터 로드
        return true // 정상적으로 실행되었음을 반환
    }

    // MARK: UISceneSession 라이프사이클

    // 새로운 씬(Scene) 세션이 생성될 때 호출됨
    func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
        // 새로운 씬을 생성할 때 사용할 설정을 선택하는 메서드
        // "Default Configuration"이라는 이름의 설정을 사용하여 씬을 생성
        return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
    }

    // 사용자가 씬 세션을 삭제했을 때 호출됨
    func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set<UISceneSession>) {
        // 앱이 실행 중이 아닐 때 삭제된 세션이 있다면, 이 메서드가 호출됨
        // 예를 들어, 멀티태스킹에서 앱을 종료했을 때 해당 씬의 데이터를 정리하는 용도로 사용
    }
}

SceneDelegate.swift

  • SceneDelegate.swift는 iOS 13 이상에서 멀티태스킹 및 씬(Scene) 기반 UI 관리를 담당하는 파일.
    앱이 실행되거나 백그라운드로 전환될 때 씬의 상태를 관리하는 역할.
import UIKit  // UIKit 프레임워크 가져오기 (UI 관련 기능 사용)

class SceneDelegate: UIResponder, UIWindowSceneDelegate {

    var window: UIWindow?  // 앱의 메인 윈도우를 관리하는 변수

    // 🔹 씬이 처음 연결될 때 호출됨 (앱 실행 시 최초 실행)
    func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
        // 씬이 정상적으로 UIWindowScene인지 확인 후 실행
        guard let _ = (scene as? UIWindowScene) else { return }
        // 만약 코드 기반 UI 설정이 필요하다면 여기서 window를 직접 생성할 수 있음
    }

    // 🔹 씬이 시스템에 의해 해제될 때 호출됨 (앱이 백그라운드로 전환되거나 세션이 삭제될 때)
    func sceneDidDisconnect(_ scene: UIScene) {
        // 씬과 관련된 리소스를 해제하는 작업 수행
        // 앱이 완전히 종료된 것이 아닐 수도 있으며, 이후 다시 연결될 수도 있음
    }

    // 🔹 씬이 활성화될 때 호출됨 (앱이 실행 중이거나 백그라운드에서 다시 돌아올 때)
    func sceneDidBecomeActive(_ scene: UIScene) {
        // 앱이 활성 상태로 전환됨
        // 예: 일시 중지된 작업 재개, UI 업데이트
    }

    // 🔹 씬이 비활성화될 때 호출됨 (전화가 오거나, 홈 화면으로 나갈 때)
    func sceneWillResignActive(_ scene: UIScene) {
        // 앱이 곧 비활성화됨 (사용자가 앱을 떠날 가능성이 있음)
        // 예: 중요한 데이터 저장, 타이머 중지
    }

    // 🔹 씬이 백그라운드에서 포그라운드로 전환될 때 호출됨 (앱이 다시 활성화될 준비를 함)
    func sceneWillEnterForeground(_ scene: UIScene) {
        // 백그라운드에서 복귀할 때 수행할 작업
        // 예: UI 업데이트, 데이터 동기화
    }

    // 🔹 씬이 포그라운드에서 백그라운드로 전환될 때 호출됨 (앱이 종료되거나 백그라운드로 들어갈 때)
    func sceneDidEnterBackground(_ scene: UIScene) {
        // 앱이 백그라운드로 전환됨
        // 예: 데이터를 저장하거나, 실행 중인 작업을 종료
    }
}

App Life Cycle

  • 앱은 실행 모드와 상태를 가짐

Not Running

  • 앱이 아직 실행되지 않았거나, 시스템에 의해 종료된 상태

Foreground Mode

  • Active : 앱이 전경에 있고 이벤트를 받고 있음. 일반적으로 사용자와 상호작용하는 동안 앱은 이 상태에 있음
  • Inactive : 앱이 전경에 있지만 이벤트를 받고 있지 않음

Background Mode

  • Running : 앱이 백그라운드에 있지만 여전히 코드를 실행. 사용자가 다른 앱으로 전환하거나 홈 화면으로 돌아갔을 때 앱은 일시적으로 이 상태에 머물게 됨
  • Suspend : 앱이 백그라운드에 있지만 코드를 실행하지 않음.
    시스템은 앱을 이상태로 자동으로 전환하며 필요에 따라 메모리를 회수하기 위해 앱을 종료시킬 수있다.

Not Running -> Active

  • 앱을 터치해서 실행이 되는 상태

Active -> Inactive -> Running

  • 앱을 활성화에서 비활성화 상태로 만든 뒤, 백그라운드에서도 계속 실행중인 상태

Active -> Inactive -> Suspend

  • 앱을 활성화에서 비활성화 상태로 만든 뒤, 백그라운드에서도 정지되어 있는 상태

Running -> Active

  • 백그라운드에서 실행 중인 앱이 다시 포어그라운드에서 활성화되는 상태

뷰(View)

  • UI의 기본 구성 요소

  • 모든 뷰는 UIKit의 UIView 클래스의 자식클래스
    UI Framework라고도 한다.
  • 부모 뷰에 추가된 뷰는 부모 뷰의 영역 내에서만 그려짐

UIView -> 화면에 보여주는 역할

UIControl -> 상호작용하는 역할

UIWindow -> 앱 UI의 배경(액자)에 해당

  • UIWindow는 일반적으로 앱의 시작 시점에 생성되며, 앱의 메인 화면을 그리는 데 사용되는 뷰 컨트롤러를 root view controller로 설정

뷰 계층(view hierarchy) 구조

컨테이너 뷰(Container View)

  • 여러 개의 뷰 컨트롤러를 포함하고, 그 사이를 전환하는 역할

  • UINavigationController
    뷰 컨트롤러 간의 계층적 네비게이션을 관리
    리스트에서 항목을 선택하면 상세 화면으로 이동하거나, 여러 단계를 거쳐 정보를 입력하는등의 작업에 사용

  • UITabBarController
    뷰 컨트롤러 간의 평행 네비게이션을 관리
    앱의 주요 기능을 각각의 탭으로 나누고 사용자가 원하는 탭을 선택하여 해당 기능을 이용할 수 있게 하는 데 사용

  • UISplitViewController
    마스터-디테일 인터페이스를 관리
    iPad와 같은 큰 화면에서 사용되며, 한 화면에 두 개의 관련된 뷰 컨트롤러를 동시에 표시하는 데 사용

AlertView와 ActionSheet

얼럿 뷰와 액션 시트

  • 사용자에게 긴급하거나 중요한 정보를 표시해주고 어떠한 조치를 할수 있는 버튼도 보여줄 수 있음
  • UIAlertView는 팝업 상자를 화면에 표시
  • UIActionSheet는 화면의 아래에서 위로 밀어 올리는 화면을 표시

ViewController

import UIKit

// ViewController 클래스는 UIViewController를 상속받아 화면을 관리하는 역할을 함
class ViewController: UIViewController {

    // viewDidLoad() 메서드는 뷰가 메모리에 로드된 후 한 번만 실행됨
    override func viewDidLoad() {
        super.viewDidLoad() // 부모 클래스의 viewDidLoad() 메서드를 호출하여 기본 설정을 수행

        // view는 UIViewController가 기본적으로 제공하는 속성으로, 현재 화면의 루트 뷰를 나타냄
        // 즉, 이 ViewController가 관리하는 메인 화면 자체를 의미함
        view.backgroundColor = UIColor.darkGray // 화면의 배경색을 어두운 회색으로 설정
    }
    
}

GPT : 0부터 255사이의 랜덤한 숫자를 구하는 코드

Int.random(in:) 사용 (가장 간단한 방법)

let randomValue = Int.random(in: 0...255)
print(randomValue)

arc4randomuniform(:) 사용 (C 스타일, 오래된 방식)

import Foundation

let randomValue = Int(arc4random_uniform(256)) // 0부터 255까지 랜덤
print(randomValue)

랜덤한 RGB 색상 만들기

import UIKit

let randomColor = UIColor(
    red: CGFloat.random(in: 0...255) / 255.0,
    green: CGFloat.random(in: 0...255) / 255.0,
    blue: CGFloat.random(in: 0...255) / 255.0,
    alpha: 1.0
)

print(randomColor) // 랜덤한 색상이 출력됨

3초 마다 바탕색이 바뀌는 코드

배경 음악 재생 + 20초 후에 자동 종료 기능 구현

import UIKit
import AVFoundation  // 오디오를 다루기 위한 프레임워크 추가


class ViewController: UIViewController {
    
    var colorChangeTimer: Timer?
    var audioPlayer: AVAudioPlayer!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // 배경 음악 재생 설정
        if let soundURL = Bundle.main.url(forResource: "bgm", withExtension: "mp3") {
            do {
                audioPlayer = try AVAudioPlayer(contentsOf: soundURL)
                audioPlayer.play()
            } catch {
                print("음악 파일 로드 또는 재생 중 에러 발생: \(error)")
            }
        }
        
        // 1초마다 반복되는 타이머 생성
        colorChangeTimer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { timer in
            // 랜덤한 빨간색, 초록색, 파란색 값을 생성
            let red = CGFloat(arc4random_uniform(256)) / 255.0
            let green = CGFloat(arc4random_uniform(256)) / 255.0
            let blue = CGFloat(arc4random_uniform(256)) / 255.0
            self.view.backgroundColor = UIColor(red: red, green: green, blue: blue, alpha: 1.0)
        }
    }
    
    override func viewDidDisappear(_ animated: Bool) {
        super.viewDidDisappear(animated)
        
        // ViewController가 사라질 때 타이머를 중지하고 nil로 설정하여 메모리 누수를 방지
        colorChangeTimer?.invalidate()
        colorChangeTimer = nil
        
        // 음악 재생 중지
        audioPlayer.stop()
    }
    
}

스위치를 정중앙에 위치시키는 방법

Horizontally in Container -> 0으로 설정시 정가운데 위치(상,하)
Vertically in Container -> 0으로 설정시 정가운데 위치(좌,우)

AutoLayOut

모든 기기에 방향까지 고려해서 거의 비슷한 모양이나 오도록 도와주는 기능

📌Auto Layout = 화면 크기에 맞게 UI를 자동 정리하는 시스템
📌 규칙(Constraints)을 정하면, 모든 기기에서 UI가 알아서 배치됨
📌 화면 크기가 변해도 요소들이 엉키지 않도록 도와줌

방법장점 👍단점 👎
스토리보드에서 Constraints 설정- 시각적으로 배치를 쉽게 조정 가능 🖼️
- 직관적인 인터페이스 제공 (마우스로 드래그 & 클릭)
- iOS 기본 기능으로 별도 코드 없이 설정 가능
- 복잡한 레이아웃일 경우 관리가 어려움 ⚠️
- 코드 기반 개발보다 유연성이 낮음
- 여러 화면 크기 대응 시 Preview만으로는 한계가 있음
코드로 NSLayoutConstraint 사용- 동적으로 레이아웃을 변경할 때 유리함 🛠️
- 복잡한 UI에서도 깔끔한 관리 가능
- 버전 충돌 걱정 없음 (스토리보드는 Xcode 업데이트 시 충돌 가능)
- 코드가 길어질 수 있음 📜
- 처음 배우기 어려울 수 있음
- 직관성이 낮아 유지보수가 힘들 수 있음
코드로 Auto Layout Anchor 사용 (추천!)- 코드가 간결하고 가독성이 좋음 ✨
- NSLayoutConstraint보다 더 쉽게 설정 가능
- 런타임에서 동적으로 조정 가능
- 스토리보드만큼 직관적이지 않음 🔍
- 마우스로 바로 확인하기 어려움
Stack View 사용- 내부 요소들의 크기와 정렬을 자동으로 조절함 📏
- 코드 없이도 쉽게 적용 가능
- 반응형 레이아웃을 만들기 쉬움
- 복잡한 배치에서는 한계가 있음 🚧
- 유연성이 부족하여 세밀한 제어가 어렵음
SwiftUI 사용- 코드가 간결하고 직관적임 💡
- 미리보기(Preview) 기능이 강력함
- 선언형 문법으로 UI 코드가 깔끔함
- iOS 13 이상에서만 사용 가능 🚫
- UIKit 기반 프로젝트와 호환성이 낮음

전광판 앱 만들기

앱 이름: LED 전광판 디스플레이

목표 사용자층

  • 콘서트나 이벤트에서 응원 메시지를 표시하려는 사용자
  • 파티, 행사 등에서 독특한 방식으로 메시지를 전달하려는 사용자
  • 공항, 역 등에서 환영 메시지를 표시하려는 사용자

주요 기능

텍스트 입력 및 표시

  • 사용자가 원하는 메시지를 입력하고, LED 전광판 스타일로 화면에 표시

  • 텍스트 스타일링
    글자 크기 조절 텍스트 색상 및 배경 색상 선택 텍스트 폰트 변경

  • 애니메이션 효과
    텍스트 스크롤, 방향 설정 (좌우, 상하), 어플가이드, 스크롤 속도 조절, 텍스트, 깜박임 효과, 이모티콘 및 아이콘 추가, 텍스트와 함께 다양한 이모티콘 및 아이콘을 추가하여 표현력 강화

  • 다국어 지원
    여러 언어로 메시지 입력 및 표시 가능
    저장 및 공유: 제작한 전광판 디자인을 이미지나 GIF로 저장 SNS나 메신저를 통해 공유

디자인 및 UI/UX 고려사항

  • 사용자 친화적인 인터페이스
    직관적인 디자인으로 누구나 쉽게 사용할 수 있도록 구성

  • 실시간 미리보기
    설정 변경 시 즉시 화면에 반영되어 사용자 편의성 향상

  • 다양한 테마 제공
    여러 가지 배경 및 텍스트 테마를 제공하여 사용자 선택 폭 확대

경쟁 앱 분석

  • 전광판 LED Scroller
    사용자 친화적인 인터페이스와 다양한 기능 제공
    글씨 크기 조정, 스크롤 속도 및 방향 설정, 색상 선택 등이 가능

  • 모두의응원 LED 전광판
    다양한 텍스트 스타일링과 애니메이션 효과 제공
    이모티콘 추가 및 다국어 지원으로 글로벌 사용자 타겟

LED 전광판 - 네온사인 - 응원간판: 글꼴 크기 조정, 다양한 텍스트 및 배경 색상, 스크롤 및 깜박임 속도 조정 등의 기능 제공

개발 일정:

1주차 : 시장 조사 및 기획
2~3주차 : UI/UX 디자인 및 프로토타입 제작
4~6주차 : 앱 개발 및 기능 구현
7주차 : 테스트 및 버그 수정
8주차 : 앱스토어 등록 및 마케팅 준비

마케팅 전략

  • SNS 활용
    인스타그램, 페이스북 등 SNS를 통해 앱 소개 및 이벤트 진행
  • 인플루언서 협업
    유명 인플루언서와 협업하여 앱 사용 후기나 튜토리얼 제작
  • 콘서트 및 이벤트와 연계
    공연 기획사나 이벤트 업체와 협력하여 앱 활용 방안 모색

정광판 결과 코드

import UIKit

class ViewController: UIViewController {
    
    @IBOutlet weak var label: UILabel!
    @IBOutlet weak var textField: UITextField!
    @IBAction func displayText(_ sender: UIButton) {
        label.text = textField.text
        startScrolling()
    }
    override func viewDidLoad() {
        super.viewDidLoad()
    }
    func startScrolling() {
        UIView.animate(withDuration: 10, delay: 0, options: [.curveLinear, .repeat], animations: {
            self.label.center.x -= self.view.bounds.width
        }, completion: nil)
    }
    
}
profile
The learning never stops. 😂

0개의 댓글