B2024001225 윤지선
14주차 수업 본문

//
// GeminiViewController.swift
// MovieYJS
//
// Created by CMAC_43 on 2026/06/02.
//
import UIKit // iOS UI 관련 기능 가져오기
// 요청(Request)에 사용할 구조체들
// API에 보낼 JSON 구조를 Swift 구조체로 표현
// Encodable: Swift 객체 → JSON 변환 가능하게 해줌
// 최상위 요청 구조: { "contents": [...] }
struct GeminiRequest: Encodable {
let contents: [RequestContent] // contents 배열
}
// contents 배열의 각 항목: { "parts": [...] }
struct RequestContent: Encodable {
let parts: [RequestPart] // parts 배열
}
// parts 배열의 각 항목: { "text": "..." }
struct RequestPart: Encodable {
let text: String // 실제 프롬프트 텍스트
}
// API가 보내주는 JSON 구조를 Swift 구조체로 표현
// Decodable: JSON → Swift 객체 변환 가능하게 해줌
// 최상위 응답 구조: { "candidates": [...] }
struct GeminiResponse: Decodable {
let candidates: [Candidate] // candidates 배열
}
// candidates 배열의 각 항목: { "content": {...} }
struct Candidate: Decodable {
let content: ResponseContent // content 객체
}
// content 객체: { "parts": [...] }
struct ResponseContent: Decodable {
let parts: [ResponsePart] // parts 배열
}
// parts 배열의 각 항목: { "text": "..." }
struct ResponsePart: Decodable {
let text: String // AI가 생성한 실제 텍스트
}
class GeminiViewController: UIViewController {
@IBOutlet weak var textField: UITextField!
@IBOutlet weak var textView: UITextView!
let apiKey = "AIzaSyALYH1nho21uQQG5JL2cWVD52BMFzYGjbc"
@IBAction func buttonTapped(_ sender: UIButton) {
// 입력값 비어있으면 종료
guard let mood = textField.text, !mood.isEmpty else { return }
// 로딩 메시지 표시
textView.text = "추천 중…"
// 키보드 내리기
view.endEditing(true)
// 영화 추천 받아오기 시작
getData(mood: mood)
}
func getData(mood: String){
let geminiURL = "https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:generateContent?key=\(apiKey)"
guard let url = URL(string: geminiURL) else { return }
let prompt = "기분이 '\(mood)'일 때 볼만한 영화 3편을 한국어로 추천해줘. 각 영화마다 제목, 장르, 추천이유를 간단히 적어줘."
let requestBody = GeminiRequest(
contents: [
RequestContent(
parts: [
RequestPart(text: prompt)
]
)
]
)
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.httpBody = try? JSONEncoder().encode(requestBody)
let session = URLSession(configuration: .default)
let task = session.dataTask(with: request) { [self] data, response, error in
if let error = error {
print(error)
return
}
guard let jsonData = data else { return }
let decoder = JSONDecoder()
do {
let decodedData = try decoder.decode(GeminiResponse.self, from: jsonData)
let text = decodedData.candidates.first?.content.parts.first?.text ?? "결과 없음"
let cleanText = text
DispatchQueue.main.async {
self.textView.text = cleanText
}
} catch {
print(error)
}
}
task.resume()
func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// Get the new view controller using segue.destination.
// Pass the selected object to the new view controller.
}
*/
}
}
9주차
JSON의 구조
두개의 메소드 사용법 철저하게
=>
tableView(_:cellForRowAt:)
tableView(_:didSelectRowAt:)
11주차
가장 중요함
어제 날짜 구하는 소스는 시험범위 X
12주차
오토레이아웃 -> 방법 여러가지인데 그 방법이 몇가지인지만 알면 됨. (5가지 방법만 알면 됨. 장단점 X)
43, 44p 제외
13주차
24p 차이점만 알고있으면 됨.
14주차
20,21p만 시험범위.