seong_hye, the developer

Swift) UIActivityViewController에 대해 알아보기 (ShareSheet) 본문

IOS/UIKit

Swift) UIActivityViewController에 대해 알아보기 (ShareSheet)

seong_hye 2022. 11. 6.

 

📘 UIActivityViewController

iOS에서 공유 시트 (Share Sheet)를 띄우기 위한 기본 UIKit 클래스

ex. 이미지, 텍스트, URL, 파일 등을 메시지, 메일, 에어드롭, 기타 앱으로 공유하고 싶을 때 사용


🔹기본 예시

class ViewController: UIViewController {
	@IBAction func shareButtonTapped(_ sender: Any) {
    	let textToShare = "공유할 텍스트입니다."
        let urlToShare = URL(string: "https://sample.com")
        let activityVC = UIActivityViewController(activityItems: [textToShare, urlToShare], applicationActivities: nil)
   	}
}

 

🔹주요 파라미터 설명

파라미터 설명
activityItems 공유할 콘텐츠 (문자열, 이미지, URL 등)
applicationActivities 사용자 정의 공유 동작 (커스텀 UiActivity)

🔹지원되는 공유 컨텐츠

타입 예시
String 일반 텍스트
UIImage 사진
URL 웹 링크, 파일 경로 등
NSData, File URL PDF, 문서 등

🔹특정 공유 옵션 제외하기

Share Sheet에서 보여지는 선택 가능한 항목을 제한할 수 있음

activityVC.excludedActivityTypes = [
	.postToFacebook,
    .print,
    ,assignToContact
]

🔹SwiftUI에서 사용법

struct ShareSheet: UIViewControllerRepresentable {
	var items: [Any]
    
    func makeUIViewController(context: Context) -> UIActivityViewController {
    	UIActivityViewController(activityItems: items, applicationActivities: nil)
    }
    
    func updateUIViewController(_ uiViewController: UIActivityViewController, context: Context) {}
}

// 사용 시
.sheet(isPresented: $showShareSheet) {
	ShareSheet(items: ["공유할 텍스트", URL(string: "https://sample.com")!])
}

🔹iPad 사용 시 유의 필요

iPad의 경우 반드시 popoverPresentationController를 설정해야 크래시를 방지할 수 있음

if let popover = activityVC.popoverPresentationController {
	popover.sourceView = sender as? UIView
    popover.sourceRect = (sender as! UIView).bounds
}

➡️ 사용 시 메모리 사용량이 급증하거나 해제되지 않는 문제가 발생할 수 있음

⚠️ 문제가 생기는 주요 원인 

1. 큰 이미지 / 영상/ PDF 등을 통째로 메모리에 로딩해서 공유할 때

2. UIActivityViewController를 강한 참조로 오래 붙잡고 있을 때

3. activityItems로 넘기는 객체가 복사되지 않고 직접 참조될 때 (특히 클로저/파일 핸들러 등)

4. SwiftUI에서 .sheet를 통해 공유 시 잘 닫히지 않거나 retain cycle 발생

 

✅ 해결 방안 예시

1. 큰 이미지 -> URL로 공유 (UIImage 대신 file URL)

let image = UIImage(named: "largeImage")!
let fileURL = FileMananger.default.temporaryDirectory.appendingPathComponent("share.jpg")
try? image.jpegData(compressionQuality: 0.8)?.write(to: fileURL)

let activityVC = UIActivityViewController(activityItems: [fileURL], applicationActivities: nil)

➡️ 이미지 전체를 메모리에 로드하지 않고, 디스크 파일로 처리하면 메모리 사용량이 급감함

 

2. SwiftUI에서 메모리 문제 방지

@Environment(/.dismiss) var dismiss

.sheet(isPresented: $showingShare) {
	ShareSheet(items: [fileURL])
    	.onDisappear {
        	// 필요시 리소스 해제
            try? FileManager.default.removeItem(at: fileURL)
        }
}

 

3. UIViewController에서 강한 참조 주의

// 캡처되지 않도록 weak self 사용
@IBAction func shareTapped(_ sender: Any) {
	let items = [text]
    let activityVC = UIActivityViewController(activityItems: items, applicationActivities: nil)
    
    activityVC.completionWithItemHandler = { [weak self] activityType, completed,returnedItems, error in
    	//메모리 해제 확인용 로깅 등
    }
    
    present(activityVC, animated: true)
}

 

✅ 메모리 문제를 줄이는 핵심 전략

- UIImage, Data, PDFDocument 직접 공유 X -> URL 공유

- 클로저 내에서 self나 큰 데이터 강한 참조 X -> [weak self]

- 파일 공유 후 사용 후 반드시 FileManager.default.removeItem

-SwiftUI에서 .sheet 사용시 .onDisappear 또는 .dismiss() 명시 

 


 

Comments