
가장 참고할만한 튜토리얼 가이드라인
IOS는 Apple 독점 운영체제, MacOS를 기반으로 한다.
Dawin 이라는 애플 자사 제품용으로 개발한 UNIX 운영체제를 밑바탕에 두고 활용함 (그 밑바닥에는 C, C++, 어셈블리, Objective-C가 깔려있는듯.)
참고 글 : MacOS architecture
당연하게도 버젼별로 기기다름
참고 : Xcode
대충 기반되어있는 IOS 아키텍처 구조는
계층(Level) 설명 Application 사용자가 실행하는 앱. 하위 API와 프레임워크를 사용하여 기능 구현. Cocoa / Cocoa Touch UI 구성 및 사용자 인터페이스 관련 기능 제공 (UIKit, MapKit 등). Media 멀티미디어 처리 계층 (AVFoundation, Core Animation, OpenGL 등). Core Services 네트워크, DB, 위치 등 핵심 서비스 제공 (Core Data, Foundation 등). Core OS 시스템 커널, 드라이버, 보안, 스레드 관리 등 운영체제 핵심 기능. Hardware 실제 기기(CPU, GPU, 저장장치 등)
이렇게 각각 레이어에서 단계별로 통신하는 느낌임
참고로 운영체제 구조 자체는 공개안함 클로즈드소스임.
더 자세한건 여기 인도형님 글 참고하셈

대충 설명하면
- Navigator
– 프로젝트 파일, 테스트 등 프로젝트에 포함되는 입력
– 디버깅 정보
– 버전 컨트롤 등
- Editor
– 소스코드
– 스토리보드를 이용한 UI 에디팅
- Inspector
– Editor에서 선택된 오브젝트에 대한 속성 등
- Output
– 실행 시 발생하는 출력
– 브레이크 포인트에서 각종 변수 등의 값
이렇게 됨 대가리박아가면서 만들면 뭐가뭔지 알거임
공식문서 추천
IOS에서는 StoryBoard는 MVC, SwiftUI는 MVVM 이나 MVI을 주로 쓴다곤 함
하지만 학교에서 배운 기본적인 MVC 패턴위주로 정리할꺼임
- Model-View-Controller
MVC(모델-뷰-컨트롤러)는 사용자 인터페이스, 데이터 및 논리 제어를 구현하는데 널리 사용되는 소프트웨어 디자인 패턴이다. 소프트웨어의 비즈니스 로직과 화면을 구분하는데 중점을 두고 있으며, 이러한 관심사 분리 는 더나은 업무의 분리와 향상된 관리를 제공한다.

- Model Layer
• 데이터를 저장하지만 사용자 인터페이스에 대하여 알지 못함
• simpleApp앱에서 모델은 문제와 정답의 목록을 가지는 문자열 리스트로 구성
• 대개 모델 레이어는 현실 세계의 사물을 대상으로 함
- View Layer
• 사용자에게 보이는 모든 객체를 포함
• 버턴, 텍스트필드, 슬라이더 등이 있음
• 대부분 이미 만들어져 있는 것을 그대로 사용함
- Controller Layer
• 응용 프로그램을 관리
• 사용자에게 보이는 뷰를 구성
• 뷰와 모델을 연결하고 동기화 함
님들이 StoryBoard로 프로젝트 만들면 대충 저런 트리가 나올거임
사실 이거보다 더 양이많음 중요한 부분만 추려와봄
.
├── IosStoryBoard/ # 앱의 메인 소스 코드 디렉토리
│ ├── AppDelegate.swift # 앱 생명주기 관리
│ ├── SceneDelegate.swift # 씬(UI 인스턴스) 생명주기 관리 (iOS 13+)
│ ├── ViewController.swift # 화면 컨트롤러 (Controller)
│ ├── Base.lproj/ # 기본 인터페이스 파일 디렉토리
│ │ ├── Main.storyboard # 메인 UI 인터페이스 (View)
│ │ └── LaunchScreen.storyboard # 시작 화면 (View)
│ ├── Assets.xcassets/ # 앱 리소스 (이미지, 색상 등)
│ └── Info.plist # 앱 설정 정보
└── IosStoryBoard.xcodeproj/ # Xcode 프로젝트 파일
└── project.pbxproj # 프로젝트 설정 파일
아래는 대략적인 그림

Xcode에서 자체적으로 MVC패턴을 만들어주기 때문에 가볍게 분석해볼거임

import Foundation
// var landmarks: [Landmark] = load("landmarkData.json")
func load<T: Decodable>(_ filename: String) -> T {
let data: Data
guard let file = Bundle.main.url(forResource: filename, withExtension: nil)
else {
fatalError("Couldn't find \(filename) in main bundle.")
}
do {
data = try Data(contentsOf: file)
} catch {
fatalError("Couldn't load \(filename) from main bundle:\n\(error)")
}
do {
let decoder = JSONDecoder()
return try decoder.decode(T.self, from: data)
} catch {
fatalError("Couldn't parse \(filename) as \(T.self):\n\(error)")
}
}
후술 하겠지만 이런것처럼 데이터 처리할때 주로 만들어짐
Controller
– ViewController.swift: 화면과 사용자 상호작용을 관리하는 주요 컨트롤러
– AppDelegate.swift: 앱의 생명주기를 관리
– SceneDelegate.swift: iOS 13부터 도입된 멀티 윈도우 지원을 위한 씬 생명주기 관리

View
– Main.storyboard: 앱의 주요 UI 인터페이스를 설계하는 파일
– LaunchScreen.storyboard: 앱 시작 시 표시되는 화면
– Assets.xcassets: 앱에서 사용하는 이미지, 색상 등의 리소스

그래서 대강 전체적으로 보면

이런 모습이됨
참고 : claude가 알려준 IOS에서 쓰는 패턴들
아키텍처 패턴 스토리보드/UIKit SwiftUI 주요 특징 MVC ✅ 매우 일반적 ⚠️ 가능하나 권장되지 않음 • UIKit의 기본 패턴
• 컨트롤러에 코드가 집중되는 경향MVVM ✅ 일반적 ✅ 매우 일반적 • 뷰 모델을 통한 데이터 바인딩
• SwiftUI의 @ObservableObject와 자연스럽게 통합MVP ✅ 사용됨 ⚠️ 드물게 사용 • 프레젠터를 통한 뷰 업데이트
• ViewController를 View로 취급VIPER ✅ 복잡한 앱에서 사용 ⚠️ 거의 사용되지 않음 • 높은 모듈화
• 5개 구성요소로 책임 분리Clean Architecture ✅ 대규모 앱에서 사용 ✅ 사용됨 • 계층적 의존성 구조
• 유스케이스 중심 설계Coordinator ✅ 화면 전환에 자주 사용 ⚠️ SwiftUI 네비게이션에 적용 가능 • 화면 전환 로직 분리
• 화면 흐름의 중앙 관리Redux/Flux ⚠️ 일부 사용 ✅ 자주 사용 • 중앙 집중식 상태 관리
• 단방향 데이터 흐름MVI ⚠️ 드물게 사용 ✅ 사용 증가 추세 • Intent를 통한 사용자 액션 처리
• 단방향 데이터 흐름TCA (The Composable Architecture) ⚠️ 거의 사용되지 않음 ✅ 인기 증가 중 • 상태, 액션, 환경, 리듀서로 구성
• 높은 테스트 용이성

이런 앱을 만들어볼거임


Xcode는 안드로이드처럼 .xml파일을 계속 만드는게아님
하나의 파일 (.storyboard) 안에 여러개의 화면을 만드는거임
안드로이드 = 1화면 1 xml
Xcode = 1개 스토리보드, n개 View Controller Scene
예시로 들자면
안드로이드는 이런구조

- MainActivity.kt + activity_main.xml: 앱의 메인 컨테이너
여러 Fragment를 관리:
HomeFragment.kt + fragment_home.xml
FeedFragment.kt + fragment_feed.xml
SearchFragment.kt + fragment_search.xml
NotificationFragment.kt + fragment_notification.xml
bottom_navigation.xml: 하단 탐색바 레이아웃
저렇게 XML 각각 만드는거에 비해
Xcode에서는

- Main.storyboard: 앱의 메인 흐름
– MainTabBarController: 앱의 메인 탭바를 관리하는 컨트롤러
– HomeViewController: 홈 화면을 담당하는 컨트롤러- Authentication.storyboard: 로그인/회원가입 화면
- Profile.storyboard: 사용자 프로필 관련 화면
- Settings.storyboard: 설정 관련 화면
- Onboarding.storyboard: 앱 초기 온보딩 화면
큰 틀에서 여러개 만드는 느낌
코드로 보면
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="13122.16" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="BYZ-38-t0r">
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13104.12"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
<!--View Controller-->
<scene sceneID="tne-QT-ifu">
<objects>
<viewController id="BYZ-38-t0r" customClass="ViewController" customModuleProvider="target" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" xcode11CocoaTouchSystemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
<viewLayoutGuide key="safeArea" id="6Tk-OE-BBY"/>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
</objects>
</scene>
</scenes>
</document>
이렇게 하나의 스토리보드에서 여러개 ViewController가 있다는걸 알 수 있음
xml로 코드짜서 만들진않음 복잡해서 코드로 짜고싶으면
SwiftUI로.

Object Library에서 Button, Textfield 등등으로 화면을 구성함

– Main.storyboard를 선택하라
– 우측상단의 Object Library(+)를 클릭하라
– Label 컨트롤을 선택하여 View로 드래그&드롭하라
– 동일한 방법으로 Button, Label, Button을 View로 드래그&드롭하라
– 적절히 정렬하라
– Document Outline을 우측 그림과 같은지 확인하라.
– 좌측 상단의 삼각형을 클릭하여 실행하여 보라

Inspector 에서 다양한 기능 수행가능함

📄 - 파일 인스펙터: 파일 정보, 타겟 설정, 참조 관리
⏱️ - 히스토리 인스펙터: 파일 변경 이력 추적 및 이전 버전 복원
❓ - 도움말 인스펙터: 선택된 항목에 대한 도움말 및 문서 표시
📰 - 퀵헬프 인스펙터: 빠른 도움말 및 API 문서 액세스
≡ - 아이덴티티 인스펙터: UI 요소의 ID, 클래스, 사용자 정의 속성 설정
📐 - 사이즈 인스펙터: UI 요소의 크기, 위치, 여백, 제약조건 설정
🔄 - 연결 인스펙터: 액션, 아웃렛 연결 및 세그웨이 설정
대충 이정도만 알아보고 하나씩 써보셈

- UIViewController에서 Label에 데이터를 write하려고 하면 Label을 액세스할 수 있어야 한다. (참조)
• 안드로이드에서 label = findViewById(…)와 동일- 사용자의 View를 통하여 버턴을 클릭하면 그 내용은 UIViewController에 알려져 야한다.
• 안드로이드에서는 button.setOnClickListener(…)와 동일
한 마디로,
IBOutlet = findViewById()
- iOS: 스토리보드의 UI 요소(예: Label)를 코드에서 참조하기 위해 IBOutlet으로 연결.
- 안드로이드: XML 레이아웃의 UI 요소를 코드에서 참조하기 위해 findViewById()를 사용.
IBAction = setOnClickListener()
- iOS: 버튼 클릭 같은 사용자 이벤트를 처리하기 위해 IBAction 메서드를 연결.
- 안드로이드: 버튼 클릭을 처리하기 위해 setOnClickListener()를 설정.
정도 됨 아래는 부가설명


저거 눌러서 두개 여셈
아니면
동시 오픈 방법
- Main.storyboard를 오픈한다
- 이 상태에서 option 및 ViewController.swift를 클릭 한다



혹은 원래 있던 거면 이렇게 연결할 수도 있긴함






결과

Connection Inspector

var questions = [
"대한민국의 수도는 무엇인가요?",
"한국 청년들에게 가장 인기있는 대학은 무슨 대학인가요?",
"7+21은 얼마인가요?"
]
var answers = [
"서울",
"한셔대학교",
"28"
]
var currentIndex = 0
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
questionLabel.text = questions[currentIndex]
// questionLabel의 Text 안에다 questions 배열의 현재 인덱스 값이 들어감
}
안드로이드로 치면 onCreate() 함수임
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
이부분은 생명주기랑 연결도 되어있어서 나중에 설명함
@IBAction func nextQuestion(_ sender: UIButton) {
currentIndex = (currentIndex+1)%questions.count
questionLabel.text = questions[currentIndex]
}
@IBAction func showAnswer(_ sender: UIButton) {
answerLabel.text = answers[currentIndex]
}

처음 버튼을 누르면 Model에서 설정한 문제가 나오고,
두번째 버튼을 누르면 그에대한 대답이 나온다
만약 글씨가 짤리거나 그러면
아래 참고
아래는 전체 코드
import UIKit
class ViewController: UIViewController {
@IBOutlet weak var qustionLabel: UILabel!
@IBOutlet weak var answerLabel: UILabel!
var questions = [
"대한민국의 수도는 무엇인가요?",
"한국 청년들에게 가장 인기있는 대학은 무슨 대학인가요?",
"7+21은 얼마인가요?"
]
var answers = [
"서울",
"한셔대학교",
"28"
]
var currentIndex = 0
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
qustionLabel.text = questions[currentIndex]
}
@IBAction func nextQuetion(_ sender: UIButton) {
currentIndex = (currentIndex+1)%questions.count
qustionLabel.text = questions[currentIndex]
}
@IBAction func showQuestion(_ sender: UIButton) {
answerLabel.text = answers[currentIndex]
}
}
struct QuestionAnswer {
let question: String
let answer: String
}
class QuestionBank {
// 모든 질문-답변 항목을 저장하는 배열. private(set)으로 외부에서 읽기만 가능하게 설정
private(set) var items: [QuestionAnswer]
// 현재 선택된 질문-답변의 인덱스. private(set)으로 외부에서 읽기만 가능하게 설정
private(set) var currentIndex: Int = 0
/**
* 초기화 메서드
* @param items 초기 질문-답변 목록. 기본값은 빈 배열
*/
init(items: [QuestionAnswer] = []) {
self.items = items
}
/**
* 계산 프로퍼티: 현재 선택된 질문-답변 항목을 반환
* - 배열이 비어있을 경우 nil 반환
*/
var currentItem: QuestionAnswer? {
guard !items.isEmpty else { return nil }
return items[currentIndex]
}
/**
* 다음 질문-답변으로 이동하는 메서드
* - 마지막 항목에서 호출 시 첫 번째 항목으로 순환
*/
func moveToNext() {
guard !items.isEmpty else { return }
currentIndex = (currentIndex + 1) % items.count
}
/**
* 이전 질문-답변으로 이동하는 메서드
* - 첫 번째 항목에서 호출 시 마지막 항목으로 순환
*/
func moveToPrevious() {
guard !items.isEmpty else { return }
currentIndex = (currentIndex - 1 + items.count) % items.count
}
}
class ViewController: UIViewController {
// UI 요소와 연결된 아웃렛 변수들
@IBOutlet weak var questionLabel: UILabel! // 질문을 표시할 레이블
@IBOutlet weak var answerLabel: UILabel! // 답변을 표시할 레이블
/**
* 질문-답변 데이터를 관리하는 모델 컨테이너 인스턴스
* - 샘플 데이터로 초기화됨
*/
let questionBank = QuestionBank(items: [
QuestionAnswer(question: "대한민국의 수도는 무엇인가요?", answer: "서울"),
QuestionAnswer(question: "한국 청년들에게 가장 인기있는 대학은 무슨 대학인가요?", answer: "한셔대학교"),
QuestionAnswer(question: "7+21은 얼마인가요?", answer: "28")
])
/**
* 뷰 컨트롤러의 뷰가 메모리에 로드된 후 호출되는 메서드
* - 초기 UI 설정을 담당
*/
override func viewDidLoad() {
super.viewDidLoad()
updateUI() // UI 초기화
}
/**
* UI 업데이트 메서드
* - 현재 선택된 질문-답변에 따라 레이블 텍스트를 업데이트
* - 데이터가 없는 경우 기본 메시지 표시
*/
func updateUI() {
if let currentItem = questionBank.currentItem {
questionLabel.text = currentItem.question
answerLabel.text = currentItem.answer
} else {
questionLabel.text = "질문이 없습니다"
answerLabel.text = ""
}
}
/**
* 다음 버튼 탭 이벤트 처리 메서드
* - Interface Builder에서 연결된 액션 메서드
* @param sender 이벤트를 발생시킨 버튼
*/
@IBAction func nextButtonTapped(_ sender: UIButton) {
questionBank.moveToNext() // 모델 업데이트
updateUI() // UI 업데이트
}
/**
* 이전 버튼 탭 이벤트 처리 메서드
* - Interface Builder에서 연결된 액션 메서드
* @param sender 이벤트를 발생시킨 버튼
*/
@IBAction func previousButtonTapped(_ sender: UIButton) {
questionBank.moveToPrevious() // 모델 업데이트
updateUI() // UI 업데이트
}
}
안드로이드의 Splash 화면이랑 유사하다 생각하셈

App Icons & Launch Images → Launch Screen File에서 LaunchScreen 선택

원하는 .png 파일 Navigator에 복사.

LaunchScreen.storyboard를 오픈
Object Library에서 Image 컨 트롤을 drag하여 LaunchScreen.storyboard 중앙 에 적절히 놓기


Image컨트롤을 선택하여 속성 창에서 appleicon.jpg를 선택

Navigator에서 AppDelegate.swift를 선택하여 오픈하여 아래 코드를 삽입
참고로 AppDelegate는 iOS 앱의 생명주기를 관리하는 중요한 클래스임.
그래서 아래와같이 쓰레드를 정지시키는 코드를 쓰는거고
Thread.sleep(forTimeInterval: 2.0)
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
Thread.sleep(forTimeInterval: 2.0)// <- 여기다 삽입
return true
}
님이 forTimeInterval에 지정한 시간만큼 로고가 뜸

참고 iOS LaunchScreen vs 안드로이드 스플래시 화면
- 코드 실행: iOS 불가능 / 안드로이드 가능
- 표시 기간 제어: iOS 자동 / 안드로이드 수동 가능
- 애니메이션: iOS 불가능 / 안드로이드 가능
- 구현 방식: iOS storyboard / 안드로이드 Activity 또는 API
???: 아니 Thread.sleep(forTimeInterval: 2.0)
이코드는 뭔가요
시간 제어가 아니라
앱의 생명주기 중, 초기화 과정을 인위적으로 지연시키는 방법임
결론적으론 잘 안쓴다는거 타이머나 비동기처리 많이씀

처음에 이렇게 뜰거임 이게 기본 배경
iOS는 기기별 아이콘의 크기를 정해 놓음
여러 기기에 적용하기 위해서는 적용을 원하는 기기에 해당하는 아이콘을 전부 준비하여야 함

Figma에서 아이콘을 만들던 긴빠이치던 알아서하고

본인은 컴포즈로 했음

다운받아서 압축파일 열면 저렇게 나온다
IOS ㄱㄱ

여러가지 상황(설정,알림때 앱모양 등등..)을 대비하여 넣어야하지만
기본으로 60x60 2배3배 정도만 넣어주고 실행시키고 꺼보셈

완성