Operation 문제 #2
Replies: 4 comments 1 reply
Operation의 4가지 상태를 설명하고, 각 상태의 특징과 전환 조건을 자세히 설명하세요.
Operation의 주요 특징 3가지를 설명하고, 각 특징이 동시성 프로그래밍에 미치는 영향을 논하세요.
OperationQueue의 maxConcurrentOperationCount 속성의 의미와 동시성 관리에 대해 설명하세요.
Operation을 상속받아 Custom Operation을 구현할 때 고려해야 할 주요 메서드와 프로퍼티는 무엇인가요?
Operation과 GCD(Grand Central Dispatch)의 주요 차이점 3가지를 설명하세요.
Operation을 이용해서 아래와 동작하는 코드를 작성하시오.
import UIKit
class AsyncOperation: Operation {
enum State: String {
case ready, executing, finished
fileprivate var keyPath: String {
return "is\(rawValue.capitalized)"
}
}
var state = State.ready {
willSet {
willChangeValue(forKey: newValue.keyPath)
willChangeValue(forKey: state.keyPath)
}
didSet {
didChangeValue(forKey: oldValue.keyPath)
didChangeValue(forKey: state.keyPath)
}
}
}
extension AsyncOperation {
override var isReady: Bool {
super.isReady && state == .ready
}
override var isExecuting: Bool {
state == .executing
}
override var isFinished: Bool {
state == .finished
}
override var isAsynchronous: Bool {
true
}
override func start() {
if isCancelled {
state = .finished
return
}
main()
state = .executing
}
override func cancel() {
super.cancel()
state = .finished
}
}
protocol ImageProvider {
var image: UIImage? { get }
}
final class DownloadOperation: AsyncOperation {
var inputUrl: String?
var outputImage: UIImage?
override func main() {
guard let inputUrl, let url = URL(string: inputUrl),
isCancelled == false else {
return
}
URLSession.shared.dataTask(with: url) { data, _, error in
defer {
self.state = .finished
}
if let error {
return
}
guard let data,
let image = UIImage(data: data) else {
return
}
self.outputImage = image
}.resume()
}
}
extension DownloadOperation: ImageProvider {
var image: UIImage? { outputImage }
}
extension UIImage {
func convertToGrayScale() -> UIImage {
let context = CIContext(options: nil)
guard let currentFilter = CIFilter(name: "CIPhotoEffectMono"),
let ciImage = CIImage(image: self) else { return self }
currentFilter.setValue(ciImage, forKey: kCIInputImageKey)
guard let output = currentFilter.outputImage,
let cgImage = context.createCGImage(output, from: output.extent) else { return self }
return UIImage(cgImage: cgImage)
}
}
class GrayScaleOperation: Operation {
var inputImage: UIImage?
var outputImage: UIImage?
override func main() {
guard inputImage == .none,
let dependencyImageProvider = dependencies.filter({ $0 is ImageProvider }).first as? ImageProvider else {
return
}
inputImage = dependencyImageProvider.image
outputImage = inputImage?.convertToGrayScale()
}
}
let urlString = "https://github.com/yavuzceliker/sample-images/blob/main/images/image-1.jpg?raw=true"
let downloadOperation = DownloadOperation()
downloadOperation.inputUrl = urlString
let grayScaleOperation = GrayScaleOperation()
grayScaleOperation.addDependency(downloadOperation)
let imageQueue = OperationQueue()
imageQueue.addOperations(
[downloadOperation, grayScaleOperation],
waitUntilFinished: true
)
downloadOperation.outputImage
grayScaleOperation.outputImage |
Operation의 4가지 상태를 설명하고, 각 상태의 특징과 전환 조건을 자세히 설명하세요.
Operation의 주요 특징 3가지를 설명하고, 각 특징이 동시성 프로그래밍에 미치는 영향을 논하세요.
OperationQueue의 maxConcurrentOperationCount 속성의 의미와 동시성 관리에 대해 설명하세요.오퍼레이션 큐가 몇개의 쓰레드에 작업을 배치할지 지정할 수 있는 프로퍼티. defualt는 -1로, 따로 카운트를 설정해주지 않으면 OS 에서 알아서 결정하지만, 2,3 등의 숫자를 정해주면 지정된 수만큼의 쓰레드 내에서 동작하도록 한다. 1일 경우에 메인쓰레드에서만 사용하도록 한다. Operation을 상속받아 Custom Operation을 구현할 때 고려해야 할 주요 메서드와 프로퍼티는 무엇인가요?input, output, main() Operation과 GCD(Grand Central Dispatch)의 주요 차이점 3가지를 설명하세요.
Operation을 이용해서 아래와 동작하는 코드를 작성하시오.
class MyOperation: Operation {
var inputImageUrl: URL
var outputUIImage: UIImage?
init(url: URL) {
self.inputImageUrl = url
}
override func main() {
if isCancelled {
return
}
guard let data = try? Data(contentsOf: inputImageUrl) else {
return
}
if isCancelled {
return
}
outputUIImage = UIImage(data: data)
}
}let operationQueue = OperationQueue()
let imageUrl = URL(string: "https:... .jpg")!
let downloadOperation = MyOperation(url: imageUrl)
downloadOperation.completionBlock = {
let downloadedImage = downloadOperation.downloadedImage
print("downloadedImage 를 흑백으로 전환하면 됩니다")
}
operationQueue.addOperation(downloadOperation) |
// 호출부 ==============================
let downloadOperation = ImageDownloadOperation(url: url)
let grayscaleOperation = ImageGrayscaleFilterOperation(imageProvider: downloadOperation)
// 의존성 추가
grayscaleOperation.addDependency(downloadOperation)
let operationQueue = OperationQueue()
operationQueue.addOperations([downloadOperation, grayscaleOperation], waitUntilFinished: false)
// =======================================// 이미지 전달을 위한 프로토콜
protocol ImageDataProvider {
var image: UIImage? { get }
}
// 추상 비동기 오퍼레이션의 정의==============================
class AsyncOperation: Operation {
// Enum 생성
enum State: String {
case ready, executing, finished
// KVO notifications을 위한 keyPath설정
fileprivate var keyPath: String {
return "is\(rawValue.capitalized)"
} // isReady/isExecuting/isFinished
}
// 직접 관리하기 위한 상태 변수 생성
var state = State.ready {
willSet {
willChangeValue(forKey: newValue.keyPath)
willChangeValue(forKey: state.keyPath)
}
didSet {
didChangeValue(forKey: oldValue.keyPath)
didChangeValue(forKey: state.keyPath)
}
}
}
extension AsyncOperation {
// 상태속성은 모두 read-only
override var isReady: Bool {
return super.isReady && state == .ready
}
override var isExecuting: Bool {
return state == .executing
}
override var isFinished: Bool {
return state == .finished
}
override var isAsynchronous: Bool { // 무조건 true로 리턴
return true
}
override func start() {
if isCancelled {
state = .finished
return
}
main()
state = .executing
}
override func cancel() {
super.cancel()
state = .finished
}
}// 이미지 다운로드 오퍼레이션
class ImageDownloadOperation: AsyncOperation, ImageDataProvider {
let url: URL
private(set) var image: UIImage? // 프로토콜의 image -> 얘를 통해 전달
init(url: URL) {
self.url = url
}
override func main() {
if isCancelled {
finish()
return
}
let task = URLSession.shared.dataTask(with: url) { [weak self] data, response, error in
guard let self = self else { return }
defer { self.finish() } // 작업 완료 후 상태 변경
if self.isCancelled { return }
guard let data = data, error == nil else { return }
self.image = UIImage(data: data)
}
task.resume()
}
}
// 흑백 변환 오퍼레이션
class ImageGrayscaleFilterOperation: AsyncOperation {
private let imageProvider: ImageDataProvider
private(set) var outputImage: UIImage?
init(imageProvider: ImageDataProvider) {
self.imageProvider = imageProvider
}
override func main() {
if isCancelled {
return
}
guard let inputImage = imageProvider.image,
let ciImage = CIImage(image: inputImage) else {
return
}
let filter = CIFilter(name: "CIPhotoEffectMono")
filter?.setValue(ciImage, forKey: kCIInputImageKey)
if let outputCIImage = filter?.outputImage,
let cgImage = CIContext().createCGImage(outputCIImage, from: outputCIImage.extent) {
outputImage = UIImage(cgImage: cgImage)
}
}
} |
1. Operation의 4가지 상태와 특징, 전환 조건Operation은 내부적으로 4가지 상태를 가지며, 상태 전환은 OperationQueue나 수동으로 관리할 수 있다. isReady (준비 상태)
isExecuting (실행 상태)
isFinished (완료 상태)
isCancelled (취소 상태)
2. Operation의 주요 특징 3가지와 동시성 프로그래밍 영향1. 의존성(Dependency) 관리 가능
2. 취소 가능 (cancel)
3. 동기/비동기 작업 처리 가능
3. OperationQueue의 maxConcurrentOperationCount 속성• maxConcurrentOperationCount는 한 번에 실행할 수 있는 최대 Operation 개수를 의미 • 기본값은 -1이며, 이는 시스템이 적절하게 관리하도록 설정됨 (CPU 코어 수에 따라 자동 조정) • 1로 설정하면 직렬 실행(Serial Execution) 큐처럼 동작함 • 2 이상으로 설정하면 여러 작업을 병렬로 실행할 수 있음 • 이를 통해 CPU 사용량을 조절하고, 과도한 동시 실행을 방지하여 리소스를 효율적으로 관리 가능 4. Operation을 상속받아 Custom Operation을 구현할 때 고려해야 할 주요 메서드와 프로퍼티
• 실행할 작업을 정의하는 메서드 • main() 내부에서 isCancelled 체크 후 조기 종료를 고려해야 함
• isExecuting, isFinished를 수동으로 관리해야 함 • main() 대신 직접 실행 로직을 작성해야 함
• 기본적으로 false이므로, 비동기 작업을 하려면 true로 설정해야 함
• 취소 요청을 확인하고 실행 중인 작업을 중단할 수 있도록 구현해야 함
• addDependency(_:)를 활용하여 실행 순서를 조정 가능 5. Operation과 GCD(Grand Central Dispatch)의 주요 차이점 3가지
6. Operation을 이용한 이미지 다운로드 및 흑백 변환 코드import UIKit
// MARK: - 1. 이미지 다운로드 작업
class ImageDownloadOperation: Operation {
private let imageURL: URL
var downloadedImage: UIImage?
init(imageURL: URL) {
self.imageURL = imageURL
}
override func main() {
if isCancelled { return }
guard let data = try? Data(contentsOf: imageURL) else { return }
if isCancelled { return }
downloadedImage = UIImage(data: data)
}
}// MARK: - 2. 흑백 변환 작업
class GrayscaleFilterOperation: Operation {
var inputImage: UIImage?
var outputImage: UIImage?
init(image: UIImage?) {
self.inputImage = image
}
override func main() {
if isCancelled { return }
guard let inputImage = inputImage else { return }
let filter = CIFilter(name: "CIPhotoEffectMono")
let ciImage = CIImage(image: inputImage)
filter?.setValue(ciImage, forKey: kCIInputImageKey)
if isCancelled { return }
if let outputCIImage = filter?.outputImage,
let cgImage = CIContext().createCGImage(outputCIImage, from: outputCIImage.extent {
outputImage = UIImage(cgImage: cgImage)
}
}
}// MARK: - 실행 코드
let imageURL = URL(string: "https://example.com/sample.jpg")!
let downloadOp = ImageDownloadOperation(imageURL: imageURL)
let filterOp = GrayscaleFilterOperation(image: nil)
// downloadOp가 끝난 후 filterOp가 실행되도록 설정
filterOp.addDependency(downloadOp)
let operationQueue = OperationQueue()
operationQueue.addOperations([downloadOp, filterOp], waitUntilFinished: true)
// 변환된 이미지 출력
if let finalImage = filterOp.outputImage {
print("흑백 이미지 변환 완료")
} |
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Operation의 4가지 상태를 설명하고, 각 상태의 특징과 전환 조건을 자세히 설명하세요.
Operation의 주요 특징 3가지를 설명하고, 각 특징이 동시성 프로그래밍에 미치는 영향을 논하세요.
OperationQueue의 maxConcurrentOperationCount 속성의 의미와 동시성 관리에 대해 설명하세요.
Operation을 상속받아 Custom Operation을 구현할 때 고려해야 할 주요 메서드와 프로퍼티는 무엇인가요?
Operation과 GCD(Grand Central Dispatch)의 주요 차이점 3가지를 설명하세요.
Operation을 이용해서 아래와 동작하는 코드를 작성하시오.
All reactions