카테고리 없음

iOS 프로젝트

jong133 2026. 6. 8. 17:55

 

 

 

 

 

 

 

 

 

//

//  AppDelegate.swift

//  MovieLJY

//

//  Created by comsoft on 2026/05/04.

//

 

import UIKit

 

@main

class AppDelegate: UIResponder, UIApplicationDelegate {

 

 

 

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {

        // Override point for customization after application launch.

        return true

    }

 

    // MARK: UISceneSession Lifecycle

 

    func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {

        // Called when a new scene session is being created.

        // Use this method to select a configuration to create the new scene with.

        return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)

    }

 

    func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set<UISceneSession>) {

        // Called when the user discards a scene session.

        // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.

        // Use this method to release any resources that were specific to the discarded scenes, as they will not return.

    }

 

 

}

 

AppDelegate.swift

import UIKit

 

// MARK: - 축구선수 데이터 구조체

struct FootballPlayer {

    let rank: String

    let name: String

    let team: String

    let description: String

}

 

class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {

 

    @IBOutlet weak var table: UITableView!

 

    // MARK: - 수동 데이터 (TOP 10)

    let players: [FootballPlayer] = [

        FootballPlayer(rank: "1", name: "킬리안 음바페", team: "레알 마드리드",

                       description: "폭발적인 스피드와 결정력, 2024/25 레알 마드리드 이적"),

        FootballPlayer(rank: "2", name: "에를링 할란드", team: "맨체스터 시티",

                       description: "역대급 득점력, 시즌 50골 이상 기록"),

        FootballPlayer(rank: "3", name: "비니시우스 주니오르", team: "레알 마드리드",

                       description: "현란한 드리블과 빠른 발, 챔피언스리그 결승 골"),

        FootballPlayer(rank: "4", name: "주드 벨링엄", team: "레알 마드리드",

                       description: "미드필더의 새로운 기준, 득점력과 창의성 겸비"),

        FootballPlayer(rank: "5", name: "필 포든", team: "맨체스터 시티",

                       description: "잉글랜드 최고의 재능, 섬세한 기술과 침착한 마무리"),

        FootballPlayer(rank: "6", name: "하미 살라", team: "리버풀",

                       description: "꾸준한 득점과 어시스트, 리버풀의 레전드"),

        FootballPlayer(rank: "7", name: "리오넬 메시", team: "인테르 마이애미",

                       description: "역대 최고의 선수, 발롱도르 8회 수상"),

        FootballPlayer(rank: "8", name: "크리스티아누 호날두", team: "알나스르",

                       description: "통산 900골 돌파, 불굴의 득점 본능"),

        FootballPlayer(rank: "9", name: "로드리", team: "맨체스터 시티",

                       description: "발롱도르 수상, 완벽한 수비형 미드필더"),

        FootballPlayer(rank: "10", name: "라민 야말", team: "FC 바르셀로나",

                       description: "17세 유럽선수권 우승, 차세대 최고 유망주")

    ]

 

    // MARK: - TableView

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {

        return players.count

    }

 

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

        let cell = tableView.dequeueReusableCell(withIdentifier: "myCell", for: indexPath) as! MyTableViewCell

 

        let player = players[indexPath.row]

        cell.moiveName.text = "[\(player.rank)위] \(player.name)"

        cell.audiCount.text = "🏟 \(player.team)"

        cell.audiAccumulate.text = "⭐ \(player.description)"

        return cell

    }

 

    func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {

        return "⚽ 2024/25 시즌 세계 축구선수 TOP 10 ⚽"

    }

 

    func tableView(_ tableView: UITableView, titleForFooterInSection section: Int) -> String? {

        return "made by Lee"

    }

 

    func numberOfSections(in tableView: UITableView) -> Int {

        return 1

    }

 

    // MARK: - Life Cycle

    override func viewDidLoad() {

        super.viewDidLoad()

        table.delegate = self

        table.dataSource = self

        table.rowHeight = UITableView.automaticDimension

        table.estimatedRowHeight = 80

    }

 

    // MARK: - Segue

    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {

        guard let dest = segue.destination as? DetailViewController,

              let indexPath = table.indexPathForSelectedRow else { return }

        dest.movieName = players[indexPath.row].name

    }

}

 

ViewController.swift

 

//

//  DetailViewController.swift

//  MovieLJY

//

//  Created by comsoft on 2026/06/01.

//

 

import UIKit

import WebKit

 

class DetailViewController: UIViewController {

    var movieName = ""

 

    @IBOutlet weak var webView: WKWebView!

    override func viewDidLoad() {

        super.viewDidLoad()

        navigationItem.title = movieName

        let urlKorString =

            "https://www.youtube.com/results?search_query=" + movieName

        //let urlKorString =

            "https://search.naver.com/search.naver?where=nexearch&sm=top_hty&fbm=0&ie=utf8&query=" + movieName

        let urlString =

            urlKorString.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)!

        

        guard let url = URL(string: urlString) else { return }

        let request = URLRequest(url: url)

        webView.load(request)

 

        // 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.

    }

    */

 

}

DetailViewController.swift

//

//  MapViewController.swift

//  MovieLJY

//

//  Created by comsoft on 2026/06/01.

//

 

import UIKit

import WebKit

 

class MapViewController: UIViewController {

 

    @IBOutlet weak var webView: WKWebView!

    override func viewDidLoad() {

        super.viewDidLoad()

        

        let urlKorString = "https://map.naver.com/p/search/월드컵경기장"

        let urlString = urlKorString.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)!

        guard let url = URL(string:urlString) else { return }

        let request = URLRequest(url: url)

        webView.load(request)

 

 

        // 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.

    }

    */

 

}

 

MapViewController.swift

import UIKit

// MARK: - Gemini 요청 구조체 (기존 유지)

struct GeminiRequest: Encodable {

    let contents: [RequestContent]

}

struct RequestContent: Encodable {

    let parts: [RequestPart]

}

struct RequestPart: Encodable {

    let text: String

}

 

// MARK: - Gemini 응답 구조체 (기존 유지)

struct GeminiResponse: Decodable {

    let candidates: [Candidate]

}

struct Candidate: Decodable {

    let content: ResponseContent

}

struct ResponseContent: Decodable {

    let parts: [ResponsePart]

}

struct ResponsePart: Decodable {

    let text: String

}

 

// MARK: - GeminiViewController

class GeminiViewController: UIViewController {

    @IBOutlet weak var textField: UITextField!

    @IBOutlet weak var textView: UITextView!

    

    let apiKey = "AQ.Ab8RN6Lp7owFsMpveEjSYMEUW8yMQa3jy-9iZTnBUjA3h6ONjQ"

    

    @IBAction func buttonTapped(_ sender: UIButton) {

        guard let playerName = textField.text, !playerName.isEmpty else { return }

        

        textView.text = "⚽ 선수 정보 검색 중..."

        view.endEditing(true)

        

        getData(playerName: playerName)

    }

    

    func getData(playerName: 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 = """

        축구선수 '\(playerName)'에 대해 아래 형식으로 한국어로 알려줘.

        선수가 존재하지 않으면 "해당 선수를 찾을 수 없습니다"라고만 답해줘.

        

        ⚽ 선수명:

        🌍 국적:

        🎂 나이:

        📏 키:

        ⚖️ 몸무게:

        📌 포지션:

        🏟 현재 소속팀:

        🏆 주요 커리어:

        📊 대표 기록 (골, 어시스트 등):

        🌟 특징 및 플레이 스타일:

        """

        

        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 error != nil {

                DispatchQueue.main.async {

                    self.textView.text = "❌ 네트워크 오류가 발생했습니다."

                }

                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

                    .replacingOccurrences(of: "**", with: "")

                    .replacingOccurrences(of: "*", with: "")

                    .replacingOccurrences(of: "##", with: "")

                    .replacingOccurrences(of: "#", with: "")

                    .replacingOccurrences(of: "`", with: "")

                

                DispatchQueue.main.async {

                    self.textView.text = cleanText

                }

                

            } catch {

                DispatchQueue.main.async {

                    self.textView.text = "❌ 응답 처리 오류: \(error.localizedDescription)"

                }

                print(error)

            }

        }

        

        task.resume()

    }

    

    override func viewDidLoad() {

        super.viewDidLoad()

        textField.placeholder = "선수 이름 입력 (예: 손흥민, Messi)"

        textView.text = "검색할 축구선수 이름을 입력하세요 ⚽"

        textView.isEditable = false

    }

}

GeminiViewController.swift

 

 

202208026LJY.zip
0.35MB