Xcode에서 삭제시, Move to Trash로 삭제하기
identity inspector에서 class 연결하기
Alt + 클릭 : optional string 형 확인
import UIKit
import AVKit
class VideoViewController: UIViewController {
@IBAction func playVideo(_ sender: UIButton) {
let videoPath : String? = Bundle.main.path(forResource: "APT", ofType: "mp4")
let videoURL = URL(filePath: videoPath!)
let player = AVPlayer(url: videoURL)
let playerController = AVPlayerViewController()
playerController.player = player
present(playerController, animated: true)
player.play()
}
이 소스의 문제점
1. 강제 언래핑
guard let videoPath = Bundle.main.path(forResource: "APT", ofType: "mp4") else{
return
}
→ 해결) 옵셔널 대신 guard let 사용
2. URL 초기화 방식
3. 비디오 재생 시점
해결)
Enter키 누름 ↓
4. 에러 처리 부족
present 함수란?
present 함수는 iOS 앱에서 한 뷰 컨트롤러를 다른 뷰 컨트롤러 위에 모달 방식으로 표시하는 데 사용하는 메소드입니다. 이 메소드는 UIViewController 클래스의 인스턴스에서 호출됩니다.
1. 기본 정의
func present(_ viewControllerToPresent: UIViewController, animated flag: Bool, completion: (() -> Void)?)
2. 매개변수 설명
viewControllerToPresent: 표시할 뷰 컨트롤러의 인스턴스입니다. 이 뷰 컨트롤러가 현재 뷰 컨트롤러 위에 모달로 표시됩니다.
animated: 뷰 컨트롤러가 나타나는 애니메이션을 적용할지 여부를 결정하는 부울 값입니다. true로 설정하면 애니메이션 효과가 적용되고, false로 설정하면 즉시 표시됩니다.
completion: 모달 뷰 컨트롤러가 화면에 완전히 표시된 후 호출될 클로저입니다. 이 클로저는 선택사항이며, 추가적인 작업을 수행하고 싶을 때 사용할 수 있습니다.
3. 사용 예시
let secondViewController = SecondViewController()
present(secondViewController, animated: true) {
print("SecondViewController가 표시되었습니다.")
}
4. 동작 방식
모달 표시: present 메소드를 호출하면, 지정한 뷰 컨트롤러가 현재 뷰 컨트롤러 위에 모달로 표시됩니다. 모달 방식은 일반적으로 전체 화면 또는 반쯤 표시되는 형식으로 나타납니다.
종료: 모달로 표시된 뷰 컨트롤러는 dismiss 메소드를 통해 종료할 수 있습니다. dismiss는 현재 뷰 컨트롤러를 닫고, 이전 뷰 컨트롤러로 돌아갑니다.
5. 애니메이션
animated 매개변수를 true로 설정하면, 뷰 컨트롤러가 부드럽게 나타나고 사라지는 애니메이션 효과를 볼 수 있습니다. 기본적으로 iOS는 이 애니메이션을 제공합니다.
6. 예외 상황
모달 뷰 컨트롤러는 일반적으로 한 번에 하나만 표시할 수 있습니다. 이미 모달 뷰 컨트롤러가 표시되고 있을 때 또 다른 모달 뷰 컨트롤러를 표시하려고 하면, 충돌이 발생할 수 있습니다.
7. 참고 사항
모달 방식 vs. 네비게이션 방식: present 메소드는 모달 방식으로 뷰를 표시하는 데 사용되며, 이는 사용자 흐름을 변경할 때 유용합니다. 반면, 네비게이션 컨트롤러는 스택 기반의 흐름을 관리하는 데 사용됩니다.
present 함수
// <세개 소스의 차이점>
present(playerViewController, animated: true)
player.play()
self.present(playerViewController, animated: true)
player.play()
self.present(playerViewController, animated: true) {
player.play()
} //후행 클로저(trailing closure)
# 첫번째 소스
동작 방식: playerViewController를 모달로 표시한 후, 즉시 player.play()를 호출합니다.
문제점: present 메소드는 비동기적으로 동작합니다. 즉, playerViewController가 화면에 표시되기 전에 player.play()가 호출될 수 있습니다. 이 경우, 플레이어가 화면에 표시되지 않은 상태에서 비디오가 재생될 수 있습니다. 사용자 경험에 혼란을 줄 수 있습니다.
# 두번째 소스
동작 방식: 첫 번째 코드와 동일합니다. self를 명시적으로 사용했지만, 실제 동작에는 변화가 없습니다.
문제점: 여전히 present가 완료되기 전에 player.play()가 호출되므로, 비디오가 화면에 나타나기 전에 재생될 수 있습니다.
# 세번째 소스
동작 방식: present 메소드의 후행 클로저를 사용하여 player.play()를 호출합니다. 이 클로저는 playerViewController가 화면에 완전히 표시된 후에 실행됩니다.
장점: player.play()가 playerViewController가 화면에 표시된 후에 호출되므로, 비디오가 사용자에게 보이는 상태에서 재생됩니다. 사용자 경험이 향상됩니다.
# 요약
첫 번째 및 두 번째 코드: 두 코드는 동일하게 동작하며, present가 완료되기 전에 player.play()가 호출될 수 있어 비디오가 화면에 표시되지 않은 상태에서 재생될 수 있습니다.
세 번째 코드: 후행 클로저를 사용하여 player.play()를 호출하면, 비디오가 playerViewController가 화면에 표시된 후에 재생됩니다. 이는 사용자에게 더 나은 경험을 제공합니다.
결론적으로, 비디오 플레이어와 같은 UI 요소를 다룰 때는 후행 클로저를 사용하여 뷰가 화면에 표시된 후에 비디오 재생을 시작하는 것이 좋습니다.
//
// WebViewController.swift
// BMI_kej
//
// Created by 소프트웨어컴퓨터 on 2024/11/27.
//
import UIKit
import WebKit
class WebViewController: UIViewController {
@IBOutlet weak var webView: WKWebView!
@IBAction func goNaver(_ sender: UIButton) {
guard let url = URL(string: "https://m.naver.com") else { return }
let request = URLRequest(url: url)
webView.load(request)
}
override func viewDidLoad() {
super.viewDidLoad()
guard let url = URL(string: "https://m.youtube.com") else { return }
let request = URLRequest(url: url)
webView.load(request)
// Do any additional setup after loading the view.
}
}
리팩토링 하기
import UIKit
import WebKit
class WebViewController: UIViewController {
@IBOutlet weak var webView: WKWebView!
// 상수 정의
private let naverURLString = "https://m.naver.com"
private let youtubeURLString = "https://m.youtube.com"
override func viewDidLoad() {
super.viewDidLoad()
loadWebPage(urlString: youtubeURLString) // 초기 로드할 웹 페이지
}
@IBAction func goNaver(_ sender: UIButton) {
loadWebPage(urlString: naverURLString) // 네이버 웹 페이지 로드
}
// 웹 페이지 로드 메소드
private func loadWebPage(urlString: String) {
guard let url = URL(string: urlString) else {
print("유효하지 않은 URL: \(urlString)")
return
}
let request = URLRequest(url: url)
webView.load(request)
}
}
문서화된 소스
//
// WebViewController.swift
// BMI_kej
//
// Created by 소프트웨어컴퓨터 on 2024/11/27.
//
import UIKit
import WebKit
/// WebViewController는 웹 페이지를 로드하고 표시하는 UIViewController입니다.
class WebViewController: UIViewController {
// MARK: - IBOutlet
/// WKWebView 인스턴스, 웹 페이지를 표시하는 뷰입니다.
@IBOutlet weak var webView: WKWebView!
// MARK: - Actions
/// 네이버 웹 페이지로 이동하기 위한 버튼 클릭 액션입니다.
/// - Parameter sender: 버튼의 인스턴스
@IBAction func goNaver(_ sender: UIButton) {
// 네이버 웹 페이지의 URL을 생성합니다.
guard let url = URL(string: "https://m.naver.com") else { return }
// URLRequest를 생성합니다.
let request = URLRequest(url: url)
// 웹 뷰에서 요청을 로드합니다.
webView.load(request)
}
// MARK: - Lifecycle
/// 뷰가 메모리에 로드될 때 호출됩니다.
override func viewDidLoad() {
super.viewDidLoad()
// 유튜브 웹 페이지의 URL을 생성합니다.
guard let url = URL(string: "https://m.youtube.com") else { return }
// URLRequest를 생성합니다.
let request = URLRequest(url: url)
// 웹 뷰에서 요청을 로드합니다.
webView.load(request)
// 추가적인 설정을 여기에 구현할 수 있습니다.
}
}
'iOS 프로그래밍' 카테고리의 다른 글
[25.05.14_11주차] iOS 프로그래밍 실무 (0) | 2025.05.14 |
---|---|
iOS 프로그래밍_13주차 (0) | 2024.12.11 |
iOS 프로그래밍_10주차 (0) | 2024.11.20 |
iOS 프로그래밍_9주차 (0) | 2024.11.13 |
iOS 프로그래밍_8주차 (0) | 2024.11.06 |