# 마이그레이션 v5 → v6

Source: https://docs.buzzvil.com/docs/buzzbenefit-ios/v6/migration
Platform: iOS
SDK major version: v6
Language: Korean (ko)

여기에서는 Buzzvil iOS SDK v5 에서 Buzzvil iOS SDK v6 으로 마이그레이션하기 위한 설정을 안내합니다.

[GitHub 샘플 코드](https://github.com/Buzzvil/buzz-sdk-samples/tree/master/buzzvil-sdk-v6-ios)를 통해 실제 구현에 사용된 예제를 확인하세요.

> ✏️  **참고**\
> 이 가이드는 v5, v6 최신 기준으로 작성되었습니다.

> ❗️ **주의**\
> **Buzzvil SDK 6점대**는 **버즈빌 서버에서 Configuration 설정을 완료해야 정상 동작**합니다. 따라서 하위 버전에서 마이그레이션 하실때 반드시 버즈빌 담당 매니저 혹은 팀 메일(<partnership@buzzvil.com>)로 문의 부탁드립니다.

> ✅  **중요**\
> Buzzvil SDK 5점대부터는 계약 구조가 변경되었습니다. BuzzAd SDK 3점대 및 BuzzScreen SDK 4점대에서 Buzzvil SDK 6점대로 마이그레이션하는 경우, 계약서 갱신에 대해 반드시 버즈빌 담당 매니저 혹은 팀 메일(<partnership@buzzvil.com>)로 문의 부탁드립니다.

## 시작하기

### 요구 사항

1. 아래와 같이 Buzzvil SDK v6 에서 변경된 요구 사양을 확인하고 프로젝트 설정에 반영하세요.

## 요구 사양

- deployment target

  - **최소 지원**: iOS 13 이상
  - **권장 버전**: iOS 14 이상

- Xcode 16.0 이상

### 연동용 ID 발급받기

\*\*Feed(베네핏허브)\*\*가 **웹 베네핏허브**로 변경되며 더 이상 Feed Unit ID를 연동 코드에서 직접 사용하지 않습니다.

App ID와 Native Unit ID, Interstitial Unit ID는 기존과 동일하게 사용하실 수 있습니다.

### 포인트 적립 서버 연동하기

럭키박스, 미션팩이 추가되므로 [포스트백 연동 가이드](https://buzzvil.atlassian.net/wiki/spaces/BDG/pages/1756004654/API#HTTP-Request-Parameters)의 안내에 따라 요청 파라미터 처리가 필요합니다.

### SDK 설치하기

### Swift Package Manager

Swift 패키지를 가져오려면 아래 단계를 따르세요.

> ✏️  **참고**\
> CocoaPods 기반 프로젝트에서 이전하는 경우 pod deintegrate를 실행하여 Xcode 프로젝트에서 CocoaPods를 삭제합니다. CocoaPods에서 생성된 .xcworkspace 파일은 나중에 안전하게 삭제할 수 있습니다.

1. Xcode에서 `File > Add Package Dependencies`로 이동합니다.

2. Buzzvil SDK Swift Package GitHub 저장소를 검색합니다.

```
https://github.com/Buzzvil/buzzvil-ios-sdk
```

3. 사용할 버전을 선택합니다. Up to Next Minor Version(최대 다음 마이너 버전) 사용을 권장합니다.

4. 패키지 프로덕트에서 `BuzzvilSDK`를 선택합니다.

> ✏️  **참고**\
> 버즈배너를 사용하지 않는 경우 `BuzzvilSDK-WithoutThirdParty`를 선택할 수 있습니다. 이 경우 버즈배너 및 베네핏허브 내 전면 광고 기능이 제한됩니다.

패키지 종속 항목을 추가하는 방법에 관한 자세한 내용은 [Apple Developer 공식 문서](https://developer.apple.com/documentation/xcode/adding-package-dependencies-to-your-app)를 참고하세요.

### Cocoapods

Buzzvil SDK를 설치하려면 CocoaPods을 사용하여 `Podfile`에 BuzzvilSDK를 추가하세요.

> ✏️  **참고**\
> 아래의 코드 스니펫은 최신 버전의 라이브러리를 기준으로 작성되었습니다.

```
   pod 'BuzzvilSDK', '~> 6.8.0'
```

참고 - 변경 전 코드(BuzzAdBenefit SDK v5)

```actionscript3
pod 'BuzzAdBenefit', '= 5.31.3'
```

## SDK 초기화하기

### BuzzvilSDK 초기화하기

`BuzzBenefitConfig.Builder`의 생성자의 파라미터 이름이 변경 되었습니다. `appID`에서 `appId`로 변경 되었습니다.

**Swift**

```swift
import BuzzvilSDK

let config = BuzzBenefitConfig.Builder(appId: "YOUR_APP_ID")
    .build()
BuzzBenefit.shared.initialize(with: config)
```

**Objective C**

```objectivec
@import BuzzvilSDK;

BuzzBenefitConfig *config = [BuzzBenefitConfig configWith:^(BuzzBenefitConfigBuilder * _Nonnull builder) {
  builder.appId = @"YOUR_APP_ID";
}];
[[BuzzBenefit sharedInstance] initializeWith:config];
```

참고 - 변경 전 코드(BuzzAdBenefit SDK v5)

**Swift**

```swift
import BuzzvilSDK

let config = BuzzBenefitConfig.Builder(appID: "YOUR_APP_ID")
    .build()
BuzzBenefit.shared.initialize(with: config)
```

**Objective C**

```objectivec
@import BuzzvilSDK;

BuzzBenefitConfig *config = [BuzzBenefitConfig configWithBlock:^(BuzzBenefitConfigBuilder * _Nonnull builder) {
  builder.appID = @"YOUR_APP_ID";
}];
[[BuzzBenefit sharedInstance] initializeWithConfig:config];

```

#### 다크모드 설정하기

다크모드는 코드단계에서 설정하는것이 아닌 서버값을 통해서 변경하도록 업데이트 되었습니다. 이에 따라 기존에 사용하던 다크모드 관련 코드를 삭제하세요.

| 다크 모드 설정 옵션                           | 설명                                             |
| ------------------------------------- | ---------------------------------------------- |
| `BuzzBenefitUserInterfaceStyleLight`  | 시스템의 다크 모드 설정과 관계 없이 라이트 모드를 사용합니다.            |
| `BuzzBenefitUserInterfaceStyleDark`   | 시스템의 다크 모드 설정과 관계 없이 다크 모드를 사용합니다.             |
| `BuzzBenefitUserInterfaceStyleSystem` | SDK의 다크 모드 설정 `기본 값`입니다. 시스템의 다크 모드 설정을 사용합니다. |

기존에 사용하던 다크모드 설정 관련 함수를 삭제해야 합니다.

**Swift**

```swift
import BuzzvilSDK

@main
final class AppDelegate: UIResponder, UIApplicationDelegate {
  func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
    // ...생략...
    BuzzBenefit.shared.setUserInterfaceStyle(.system) // 삭제 처리
    return true
  }
}
```

**Objective C**

```objectivec
@import BuzzvilSDK;

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
  // ...생략...
  [[BuzzBenefit sharedInstance] setUserInterfaceStyle:BuzzBenefitUserInterfaceStyleSystem]; // 삭제 처리
  return YES;
}

@end
```

### 로그인 요청하기

변경 사항이 없습니다.

## 베네핏허브

### 연동

#### 베네핏허브 초기화하기

기존에 `BZVFeedConfig`를 사용하여 `BuzzBenefitConfig`에 등록하는 방식이 삭제 되었습니다. 이에 따라 `BuzzBenefitConfig`에 `setDefaultFeedConfig`함수도 삭제되어서 관련 코드를 삭제 해야 합니다.

**Swift**

```swift
import BuzzvilSDK

@main
class AppDelegate: UIResponder, UIApplicationDelegate {
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil) -> Bool {
        let config = BuzzBenefitConfig.Builder(appId: "YOUR_APP_ID")
          .build()
        BuzzBenefit.shared.initialize(with: config)
        return true
    }
}
```

**Objective-C**

```objectivec
@import BuzzvilSDK;

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    BuzzBenefitConfig *config = [BuzzBenefitConfig configWith:^(BuzzBenefitConfigBuilder * _Nonnull builder) {
      builder.appId = @"YOUR_APP_ID";
    }];
    [BuzzBenefit sharedInstance] initializeWithConfig:config]; 
    return YES;
}

@end
```

참고 - 변경 전 코드(BuzzAdBenefit SDK v5)

**Swift**

```swift
import BuzzvilSDK

@main
class AppDelegate: UIResponder, UIApplicationDelegate {
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil) -> Bool {
        let feedConfig = BZVFeedConfig { builder in
            builder.unitID = "YOUR_FEED_UNIT_ID"
        }
        let config = BuzzBenefitConfig.Builder("YOUR_APP_ID")
            .setDefaultFeedConfig(feedConfig)
            .build()
        BuzzBenefit.shared.initialize(with: config)
        return true
    }
}
```

**Objective-C**

```objectivec
@import BuzzvilSDK;

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    BZVFeedConfig *feedConfig = [BZVFeedConfig configWithBlock:^(BZVFeedConfigBuilder * _Nonnull builder) {
        builder.unitID = @"YOUR_FEED_UNIT_ID";
    }];
    BuzzBenefitConfig *config = [BuzzBenefitConfig configWithBlock:^(BuzzBenefitConfigBuilder * _Nonnull builder) {
        builder.appID = @"YOUR_APP_ID";
        builder.defaultFeedConfig = feedConfig;
    }];
    [BuzzBenefit sharedInstance] initializeWithConfig:config]; 
    return YES;
}

@end
```

#### 베네핏허브 표시하기

기존의 `BZVBuzzAdFeed`객체가 `BuzzBenefitHub`객체로 이름이 변경되었습니다. 변경된 객체를 통해 BenefitHub를 보여줍니다.

기존의 ViewController 를 받아와 하위 뷰 컨트롤러로 사용하는 방법은 동일하게 지원합니다.

**Swift**

```swift
let yourViewController = UIViewController()
let benefitHub = BuzzBenefitHub()
benefitHub.show(on: yourViewController)
```

**Objective C**

```objectivec
UIViewController *yourViewController = [[UIViewController alloc] init];
BuzzBenefitHub *benefitHub = [[BuzzBenefitHub alloc] init];
[benefitHub showOn:yourViewController];
```

참고 - 변경 전 코드(BuzzAdBenefit SDK v5)

**Swift**

```swift
/** 참고 - 변경 전 코드(BuzzAdBenefit v5) **/

let yourViewController = UIViewController()
let buzzAdFeed = BZVBuzzAdFeed { _ in }
buzzAdFeed.show(on: yourViewController)
```

**Objective-C**

```objectivec
/** 참고 - 변경 전 코드(BuzzAdBenefit v5) **/
UIViewController *yourViewController = [[UIViewController alloc] init];
BZVBuzzAdFeed *buzzAdFeed = [BZVBuzzAdFeed feedWithBlock:^(BZVBuzzAdFeedBuilder * _Nonnull builder) {}];
[buzzAdFeed showOn:yourViewController];
```

#### 기본 설정 이외의 베네핏허브 표시하기

기본 설정 이외의 베네핏허브를 표시하는 기능은 삭제 되었습니다. `BuzzBenefitHub` 객체를 선언하여 베네핏허브를 표시할 수 있습니다. 이에 사용되던 `BZVFeedConfig` 관련 코드 삭제가 필요합니다.

#### 럭키박스

베네핏허브 객체를 통해 럭키박스를 곧바로 실행할 수 있도록 기능이 업데이트 되었습니다. 기존에 제공하던 [럭키박스를 바로 표시하기](https://docs.buzzvil.com/docs/buzzbenefit-ios/v5/feed#%EB%9F%AD%ED%82%A4%EB%B0%95%EC%8A%A4%EB%A5%BC-%EB%B0%94%EB%A1%9C-%ED%91%9C%EC%8B%9C%ED%95%98%EA%B8%B0)기능을 실행하기 위한 코드가 변경 되었습니다.

**Swift**

```swift
let yourViewController = UIViewController()
let benefitHub = BuzzBenefitHub()
let benefitHubConfig = BuzzBenefitHubConfig.Builder()
  .setQueryParams(BuzzBenefitHubPage.luckyBox.toRedirectQueryParams())
  .build()
benefitHub.setConfig(benefitHubConfig)
benefitHub.show(on: yourViewController)
```

**Objective C**

```objectivec
UIViewController *yourViewController = [[UIViewController alloc] init];
BuzzBenefitHubConfig * benefithubConfig = [BuzzBenefitHubConfig configWith:^(BuzzBenefitHubConfigBuilder * _Nonnull builder) {
  builder.queryParams = [BuzzBenefitHubPage.luckyBox toRedirectQueryParams];
}];

[self.benefitHub setConfig:benefithubConfig];
[benefitHub showOn:yourViewController];
```

참고 - 변경 전 코드(BuzzAdBenefit SDK v5)

**Swift**

```swift
/** 참고 - 변경 전 코드(BuzzAdBenefit v5) **/
let yourViewController = UIViewController()
let feedConfig = BZVFeedConfig { builder in
  builder.unitID = "BENEFIT_HUB_UNIT_ID"
  builder.initialNavigationPage = .luckyBox
}
let buzzAdFeed = BZVBuzzAdFeed(block: { builder in
  builder.config = feedConfig
})
```

**Objective-C**

```objectivec
/** 참고 - 변경 전 코드(BuzzAdBenefit v5) **/
UIViewController *yourViewController = [[UIViewController alloc] init];
BZVFeedConfig *feedConfig = [BZVFeedConfig configWithBlock:^(BZVFeedConfigBuilder * _Nonnull builder) {
  builder.unitID = @"BENEFITHUB_UNIT_ID";
  builder.initialNavigationPage = BZVFeedInitialNavigationPageLuckyBox;
}];

BZVBuzzAdFeed *buzzAdFeed = [BZVBuzzAdFeed feedWithBlock:^(BZVBuzzAdFeedBuilder * _Nonnull builder) {
  builder.config = feedConfig;
}];
[buzzAdFeed showOn:yourViewController];
```

#### 미션팩

베네핏허브 객체를 통해 미션팩을 곧바로 실행할 수 있도록 기능이 업데이트 되었습니다. 기존에 제공하던 [미션팩을 바로 표시하기](https://docs.buzzvil.com/docs/buzzbenefit-ios/v5/feed#%EB%AF%B8%EC%85%98%ED%8C%A9%EC%9D%84-%EB%B0%94%EB%A1%9C-%ED%91%9C%EC%8B%9C%ED%95%98%EA%B8%B0) 기능을 실행하기 위한 코드가 변경 되었습니다.

**Swift**

```swift
let yourViewController = UIViewController()
let benefitHub = BuzzBenefitHub()
let benefitHubConfig = BuzzBenefitHubConfig.Builder()
  .setQueryParams(BuzzBenefitHubPage.missionPack.toRedirectQueryParams())
  .build()
benefitHub.setConfig(benefitHubConfig)
benefitHub.show(on: yourViewController)
```

**Objective C**

```objectivec
UIViewController *yourViewController = [[UIViewController alloc] init];
BuzzBenefitHubConfig * benefithubConfig = [BuzzBenefitHubConfig configWith:^(BuzzBenefitHubConfigBuilder * _Nonnull builder) {
  builder.queryParams = [BuzzBenefitHubPage.missionPack toRedirectQueryParams];
}];

[self.benefitHub setConfig:benefithubConfig];
[benefitHub showOn:yourViewController];
```

참고 - 변경 전 코드(BuzzAdBenefit SDK v5)

**Swift**

```swift
/** 참고 - 변경 전 코드(BuzzAdBenefit v5) **/
let yourViewController = UIViewController()
let feedConfig = BZVFeedConfig { builder in
  builder.unitID = "BENEFIT_HUB_UNIT_ID"
  builder.initialNavigationPage = .missionPack
}
let buzzAdFeed = BZVBuzzAdFeed(block: { builder in
  builder.config = feedConfig
})
```

**Objective-C**

```objectivec
/** 참고 - 변경 전 코드(BuzzAdBenefit v5) **/
UIViewController *yourViewController = [[UIViewController alloc] init];
BZVFeedConfig *feedConfig = [BZVFeedConfig configWithBlock:^(BZVFeedConfigBuilder * _Nonnull builder) {
  builder.unitID = @"BENEFITHUB_UNIT_ID";
  builder.initialNavigationPage = BZVFeedInitialNavigationPageMissionPack;
}];

BZVBuzzAdFeed *buzzAdFeed = [BZVBuzzAdFeed feedWithBlock:^(BZVBuzzAdFeedBuilder * _Nonnull builder) {
  builder.config = feedConfig;
}];
[buzzAdFeed showOn:yourViewController];
```

#### 적립내역

기존에 제공하지 않던 적립내역을 표시할 수 있는 페이지가 추가 되었습니다. 베네핏허브를 거치지 않고 곧바로 열 수 있는 기능 또한 제공 하고 있습니다.

**Swift**

```swift
let yourViewController = UIViewController()
let benefitHub = BuzzBenefitHub()
let benefitHubConfig = BuzzBenefitHubConfig.Builder()
  .setQueryParams(BuzzBenefitHubPage.history.toRedirectQueryParams())
  .build()
benefitHub.setConfig(benefitHubConfig)
benefitHub.show(on: yourViewController)
```

**Objective C**

```objectivec
UIViewController *yourViewController = [[UIViewController alloc] init];
BuzzBenefitHubConfig * benefithubConfig = [BuzzBenefitHubConfig configWith:^(BuzzBenefitHubConfigBuilder * _Nonnull builder) {
  builder.queryParams = [BuzzBenefitHubPage.history toRedirectQueryParams];
}];

[self.benefitHub setConfig:benefithubConfig];
[benefitHub showOn:yourViewController];
```

### 앱 UI 에 진입 경로 구현

`BZVFeedEntryView` 관련 기능이 삭제 되었습니다. `BuzzBenefitHub` 를 통해서 베네핏허브를 실행 시키는 방법으로 업데이트가 필요합니다. `BZVFeedEntryView` 을 사용하여 작성된 코드를 삭제 해주세요.

#### 적립 가능한 포인트 표시하기

`BZVBuzzAdFeed` 를 통해 제공되던 `availableReward` 기능이 삭제 되었습니다. `BZVBuzzAdFeed.load()` 기능또한 제거되어서 관련 코드 제거가 필요합니다.

### 추가 구현

#### 하위 뷰 컨트롤러로 베네핏허브 연동하기

기존과 동일하게 기능을 제공하지만, class 이름이 변경되었습니다. 이에 맞게 코드 업데이트가 필요합니다.

**Swift**

```swift
import BuzzvilSDK

final class ContainerViewController: UIViewController {
  let benefitHub = BuzzBenefitHub()

  override func viewDidLoad() {
    super.viewDidLoad()
    view.backgroundColor = .systemBackground

    displayContentViewController(benefitHub.getViewController())
  }
  
  private func displayContentViewController(_ contentViewController: UIViewController) {
    addChild(contentViewController)
    contentViewController.view.frame = view.bounds
    view.addSubview(contentViewController.view)
    contentViewController.didMove(toParent: self)
  }
}
```

**Objective C**

```objectivec
@import BuzzvilSDK;

@interface ContainerViewController ()

@property (nonatomic, strong, readonly) BuzzBenefitHub *benefitHub;

@end

@implementation ContainerViewController

- (void)viewDidLoad {
  [super viewDidLoad];
  
  _benefitHub = [[BuzzBenefitHub alloc] init];
  [self displayContentViewController:[_benefitHub getViewController]];
}

- (void)displayContentViewController:(UIViewController*)contentViewController {
  [self addChildViewController:contentViewController];
  contentViewController.view.frame = self.view.bounds;
  [self.view addSubview:contentViewController.view];
  [contentViewController didMoveToParentViewController:self];
}

@end
```

참고 - 변경 전 코드(BuzzAdBenefit SDK v5)

**Swift**

```swift
import BuzzvilSDK

final class ContainerViewController: UIViewController {
  let buzzAdFeed = BZVBuzzAdFeed { builder in }

  override func viewDidLoad() {
    super.viewDidLoad()
    displayContentViewController(buzzAdFeed.viewController)
  }

  private func displayContentViewController(_ contentViewController: UIViewController) {
    addChild(contentViewController)
    contentViewController.view.frame = view.bounds
    view.addSubview(contentViewController.view)
    contentViewController.didMove(toParent: self)
  }
}
```

**Objective C**

```objectivec
@import BuzzvilSDK;

@interface ContainerViewController ()

@property (nonatomic, strong, readonly) BZVBuzzAdFeed *buzzAdFeed;

@end

@implementation ContainerViewController

- (void)viewDidLoad {
  [super viewDidLoad];

  _buzzAdFeed = [BZVBuzzAdFeed feedWithBlock:^(BZVBuzzAdFeedBuilder * _Nonnull builder) {}];
  [self displayContentViewController:[_buzzAdFeed viewController]];
}

- (void)displayContentViewController:(UIViewController*)contentViewController {
  [self addChildViewController:contentViewController];
  contentViewController.view.frame = self.view.bounds;
  [self.view addSubview:contentViewController.view];
  [contentViewController didMoveToParentViewController:self];
}

@end
```

## 네이티브

### 연동

#### 1 단계. 준비하기

변경 사항이 없습니다.

#### 2 단계. 광고 레이아웃 구성하기

기존과 거의 동일하게 기능을 제공하지만, Class 이름이 변경 되었습니다.

`BZVMediaView` -> `BuzzMediaView` `BZVDefaultCtaView` -> `BuzzDefaultCtaView` `BZVNativeAd2View` -> `BuzzNativeAdView` `BZVNativeAd2ViewBinder` -> `BuzzNativeViewBinder`

더해서 `BuzzNativeViewBinder.Builder()`의 생성자에 들어가던 UnitID 값이 삭제 되고 `BuzzNative`로 이관 되었습니다.

그리고 베네핏허브 진입점으로 활용되던 `BZVNativeToFeedView`가 삭제 되었습니다. 관련 코드 삭제가 필요합니다.

**Swift**

```swift
import UIKit
import BuzzvilSDK

final class ViewController: UIViewController {
  private let nativeAdView = BuzzNativeAdView(frame: .zero)
  private let mediaView = BuzzMediaView(frame: .zero)
  private let iconImageView = UIImageView(frame: .zero)
  private let titleLabel = UILabel(frame: .zero)
  private let descriptionLabel = UILabel(frame: .zero)
  private let ctaView = BuzzDefaultCtaView(frame: .zero)

  private lazy var viewBinder = BuzzNativeViewBinder.Builder()
    .nativeAdView(nativeAdView)
    .mediaView(mediaView)
    .iconImageView(iconImageView)
    .titleLabel(titleLabel)
    .descriptionLabel(descriptionLabel)
    .ctaView(ctaView)
    .build()
  
  override func viewDidLoad() {
    super.viewDidLoad()
    
    self.view.addSubview(nativeAdView)
    nativeAdView.addSubview(mediaView)
    nativeAdView.addSubview(iconImageView)
    nativeAdView.addSubview(titleLabel)
    nativeAdView.addSubview(descriptionLabel)
    nativeAdView.addSubview(ctaView)

    // AutoLayout Constraints 설정 
    // ...
  }
}
```

**Objective-C**

```objectivec
@import BuzzvilSDK;

@interface ViewController ()

@property (nonatomic, strong, readonly) BuzzNativeAdView *nativeAdView;
@property (nonatomic, strong, readonly) BuzzMediaView *mediaView;
@property (nonatomic, strong, readonly) UIImageView *iconImageView;
@property (nonatomic, strong, readonly) UILabel *titleLabel;
@property (nonatomic, strong, readonly) UILabel *descriptionLabel;
@property (nonatomic, strong, readonly) BuzzDefaultCtaView *ctaView;
@property (nonatomic, strong, readonly) BuzzNativeViewBinder *viewBinder;

@end

@implementation ViewController

- (void)viewDidLoad {
  [super viewDidLoad];

  _nativeAdView = [[BuzzNativeAdView alloc] initWithFrame:CGRectZero];
  [self.view addSubview:_nativeAdView];

  _mediaView = [[BuzzMediaView alloc] initWithFrame:CGRectZero];
  [_nativeAdView addSubview:_mediaView];

  _iconImageView = [[UIImageView alloc] initWithFrame:CGRectZero];
  [_nativeAdView addSubview:_iconImageView];

  _titleLabel = [[UILabel alloc] initWithFrame:CGRectZero];
  [_nativeAdView addSubview:_titleLabel];

  _descriptionLabel = [[UILabel alloc] initWithFrame:CGRectZero];
  [_nativeAdView addSubview:_descriptionLabel];

  _ctaView = [[BuzzDefaultCtaView alloc] initWithFrame:CGRectZero];
  [_nativeAdView addSubview:_ctaView];
  
  _viewBinder = [BuzzNativeViewBinder viewBinderWithk:^(BuzzNativeViewBinderBuilder * _Nonnull builder) {
    builder.nativeAdView = self.nativeAdView;
    builder.mediaView = self.mediaView;
    builder.iconImageView = self.iconImageView;
    builder.titleLabel = self.titleLabel;
    builder.descriptionLabel = self.descriptionLabel;
    builder.ctaView = self.ctaView;
  }];

  // AutoLayout Constraints 설정
  // ...
}

@end
```

참고 - 변경 전 코드(BuzzAdBenefit SDK v5)

**Swift**

```swift
import UIKit
import BuzzvilSDK

final class ViewController: UIViewController {
  private let nativeAd2View = BZVNativeAd2View(frame: .zero)
  private let mediaView = BZVMediaView(frame: .zero)
  private let iconImageView = UIImageView(frame: .zero)
  private let titleLabel = UILabel(frame: .zero)
  private let descriptionLabel = UILabel(frame: .zero)
  private let ctaView = BZVDefaultCtaView(frame: .zero)
  private let nativeToFeedView = BZVNativeToFeedView(frame: .zero)

  private lazy var viewBinder = BZVNativeAd2ViewBinder
    .Builder(unitId: "YOUR_NATIVE_UNIT_ID")
    .nativeAd2View(nativeAd2View)
    .mediaView(mediaView)
    .iconImageView(iconImageView)
    .titleLabel(titleLabel)
    .descriptionLabel(descriptionLabel)
    .ctaView(ctaView)
    .build()
  
  override func viewDidLoad() {
    super.viewDidLoad()
    
    self.view.addSubview(nativeAd2View)
    nativeAd2View.addSubview(mediaView)
    nativeAd2View.addSubview(iconImageView)
    nativeAd2View.addSubview(titleLabel)
    nativeAd2View.addSubview(descriptionLabel)
    nativeAd2View.addSubview(ctaView)

    self.view.addSubView(nativeToFeedView)
    nativeToFeedView.setUnitId("YOUR_NATIVE_UNIT_ID")

    // AutoLayout Constraints 설정 
    // ...
  }
}
```

**Objective-C**

```objectivec
@import BuzzvilSDK;

@interface ViewController ()

@property (nonatomic, strong, readonly) BZVNativeAd2View *nativeAd2View;
@property (nonatomic, strong, readonly) BZVMediaView *mediaView;
@property (nonatomic, strong, readonly) UIImageView *iconImageView;
@property (nonatomic, strong, readonly) UILabel *titleLabel;
@property (nonatomic, strong, readonly) UILabel *descriptionLabel;
@property (nonatomic, strong, readonly) BZVDefaultCtaView *ctaView;
@property (nonatomic, strong, readonly) BZVNativeAd2ViewBinder *viewBinder;
@property (nonatomic, strong, readonly) BZVNativeToFeedView *nativeToFeedView;

@end

@implementation ViewController

- (void)viewDidLoad {
  [super viewDidLoad];

  _nativeAd2View = [[BZVNativeAd2View alloc] initWithFrame:CGRectZero];
  [self.view addSubview:_nativeAd2View];

  _mediaView = [[BZVMediaView alloc] initWithFrame:CGRectZero];
  [_nativeAd2View addSubview:_mediaView];

  _iconImageView = [[UIImageView alloc] initWithFrame:CGRectZero];
  [_nativeAd2View addSubview:_iconImageView];

  _titleLabel = [[UILabel alloc] initWithFrame:CGRectZero];
  [_nativeAd2View addSubview:_titleLabel];

  _descriptionLabel = [[UILabel alloc] initWithFrame:CGRectZero];
  [_nativeAd2View addSubview:_descriptionLabel];

  _ctaView = [[BZVDefaultCtaView alloc] initWithFrame:CGRectZero];
  [_nativeAd2View addSubview:_ctaView];
  
  _viewBinder = [BZVNativeAd2ViewBinder viewBinderWithBlock:^(BZVNativeAd2ViewBinderBuilder * _Nonnull builder) {
    builder.unitId = @"YOUR_NATIVE_UNIT_ID";
    builder.nativeAd2View = self.nativeAd2View;
    builder.mediaView = self.mediaView;
    builder.iconImageView = self.iconImageView;
    builder.titleLabel = self.titleLabel;
    builder.descriptionLabel = self.descriptionLabel;
    builder.ctaView = self.ctaView;
  }];

  _nativeToFeedView = [[BZVNativeToFeedView alloc] initWithFrame:CGRectZero];
  [self.view addSubview:_nativeToFeedView];

  [_nativeToFeedView setWithUnitId:@"YOUR_NATIVE_UNIT_ID"];

  // AutoLayout Constraints 설정
  // ...
}

@end
```

#### 3 단계. 광고 보여주기

광고 할당을 위해 사용되던 `BZVNativeAd2ViewBinder.bind()`함수가 사라지고 `BuzzNative.load()`함수로 변경 되었습니다. `BuzzNative`에서 할당받은 광고를 `ViewBinder`를 통해 화면에 보여지는 방식으로 업데이트 되었습니다. 이에 따라 광고 할당을 위한 코드 업데이트가 필요합니다.

**Swift**

```swift
final class ViewController: UIViewController {
  private lazy var native = BuzzNative(unitId: "YOUR_NATIVE_UNIT_ID")

  private lazy var viewBinder = BuzzNativeViewBinder.Builder()
    .nativeAdView(nativeAdView)
    .mediaView(mediaView)
    .iconImageView(iconImageView)
    .titleLabel(titleLabel)
    .descriptionLabel(descriptionLabel)
    .ctaView(ctaView)
    .build()

  override func viewDidLoad() {
    // Warning: retain cycle 방지를 위해 closure 내에서 반드시 weak self를 사용해주세요.
    native.subscribeRefreshEvents(
      onRequest: { [weak self] in
        // 광고 갱신 할당을 요청한 상태입니다.
        // 이후에는 onSuccess, onFailure 중 하나가 호출됩니다.
        // 광고 자동 갱신을 시도할 때마다 반복적으로 호출됩니다.
      }, 
      onSuccess: { [weak self] nativeAd in
        // 광고 갱신 할당에 성공하면 호출됩니다.
      }, 
      onFailure: { [weak self] error in
        // 더 이상 갱신할 수 있는 광고가 없을 때 호출됩니다.
      }
    )

    // 광고 할당을 수행합니다.
    native.load(
      onSuccess: { [weak self] nativeAd in
        // 초기 광고 할당에 성공하면 호출됩니다.
      }, 
      onFailure: { [weak self] error in
        // 초기 광고 할당에 실패하면 호출됩니다.
      }
    )

    // 할당된 광고 표시를 자동으로 수행합니다.
    viewBinder.bind(native)
  }
}
```

**Objective-C**

```objectivec
@interface ViewController ()

@property (nonatomic, strong, readonly) BuzzNative *native;
@property (nonatomic, strong, readonly) BuzzNativeViewBinder *viewBinder;

@end

@implementation ViewController

- (void)viewDidLoad {
  // ...생략...

  // Warning: retain cycle 방지를 위해 weak self를 사용해주세요.
  __weak typeof(self) weakSelf = self;
  [_viewBinder subscribeRefreshEvents:^{
    // 광고 갱신 할당을 요청한 상태입니다.
    // 이후에는 onSuccess, onFailure 중 하나가 호출됩니다.
    // 광고 자동 갱신을 시도할 때마다 반복적으로 호출됩니다.
    __strong typeof(self) strongSelf = weakSelf;
    if (strongSelf) {
      // ...
    }
  } onSuccess:^(BuzzNativeAd * _Nonnull nativeAd) {
    // 광고 갱신 할당에 성공하면 호출됩니다.
    __strong typeof(self) strongSelf = weakSelf;
    if (strongSelf) {
      // ...
    }
  } onError:^(NSError * _Nonnull error) {
    // 더 이상 갱신할 수 있는 광고가 없을 때 호출됩니다.
    __strong typeof(self) strongSelf = weakSelf;
    if (strongSelf) {
      // ...
    }
  }];

  // 광고 할당을 수행합니다.
  [_native loadOnSuccess:^(BuzzNativeAd * _Nonnull nativeAd) {
    // 초기 광고 할당에 성공하면 호출됩니다.
    __strong typeof(self) strongSelf = weakSelf;
    if (strongSelf) {
      // ...
    }
  } onFailure:^(NSError * _Nonnull error) {
    // 초기 광고 할당에 실패하면 호출됩니다.
    __strong typeof(self) strongSelf = weakSelf;
    if (strongSelf) {
      // ...
    }
  }];

  // 할당된 광고 표시를 자동으로 수행합니다.
  [_viewBinder bindWithNative:_native];
}

@end
```

참고 - 변경 전 코드(BuzzAdBenefit SDK v5)

**Swift**

```swift
final class ViewController: UIViewController {
  // ...생략...
  private let activityIndicatorView = UIActivityIndicatorView(frame: .zero)

  override func viewDidLoad() {
    // ...생략...

    // Warning: retain cycle 방지를 위해 closure 내에서 반드시 weak self를 사용해주세요.
    viewBinder.subscribeEvents(onRequest: { [weak self] in
      // 광고 할당을 요청한 상태입니다.
      // 이후에는 onNext, onCompleted, onError 중 하나가 호출됩니다.
      // 광고 자동 갱신을 시도할 때마다 반복적으로 호출됩니다.
      // 로딩 화면 등을 구현할 수 있습니다.
      self?.activityIndicatorView.startAnimating()
    }, onNext: { [weak self] nativeAd2 in
      // 광고 할당에 성공하면 호출됩니다.
      // 이후에 광고 갱신 시 onRequest가 다시 호출됩니다.
      // 광고 자동 갱신을 성공할 때마다 반복적으로 호출됩니다.
      // 로딩 화면 등을 구현한 경우, 여기에서 로딩을 종료합니다.
      self?.activityIndicatorView.stopAnimating()
    }, onError: { [weak self] error in
      // 최초 광고 할당에 실패하면 호출됩니다.
      // 로딩 화면 등을 구현한 경우, 여기에서 로딩을 종료합니다.
      self?.activityIndicatorView.stopAnimating()
      // NativeAd2View를 숨기거나, Error UI로 대체할 수 있습니다.
      print("Failed to load ad by \(error.localizedDescription).")
    }, onCompleted: { [weak self] in
      // 더 이상 갱신할 수 있는 광고가 없을 때 호출됩니다.
      // 로딩 화면 등을 구현한 경우, 여기에서 로딩을 종료합니다.
      self?.activityIndicatorView.stopAnimating()
    })

    // 광고 할당 및 표시를 자동으로 수행합니다.
    viewBinder.bind()
  }
}
```

**Objective-C**

```objectivec
@interface ViewController ()
// ...생략...
@property (nonatomic, strong, readonly) UIActivityIndicatorView *activityIndicatorView;

@end

@implementation ViewController

- (void)viewDidLoad {
  // ...생략...

  // Warning: retain cycle 방지를 위해 weak self를 사용해주세요.
  __weak typeof(self) weakSelf = self;
  [_viewBinder subscribeEventsOnRequest:^{
    // 광고 할당을 요청하면 호출됩니다.
    // 이후에는 onNext, onCompleted, onError 중 하나가 호출됩니다.
    // 광고 자동 갱신을 시도할 때마다 반복적으로 호출됩니다.
    // 로딩 화면 등을 구현할 수 있습니다.
    __strong typeof(self) strongSelf = weakSelf;
    if (strongSelf) {
      [strongSelf.activityIndicatorView startAnimating];
    }
  } onNext:^(BZVNativeAd2 * _Nonnull nativeAd2) {
    // 광고 할당에 성공하면 호출됩니다.
    // 이후에 광고 갱신 시 onRequest가 다시 호출됩니다.
    // 광고 자동 갱신을 성공할 때마다 반복적으로 호출됩니다.
    // 로딩 화면 등을 구현한 경우, 여기에서 로딩을 종료합니다.
    __strong typeof(self) strongSelf = weakSelf;
    if (strongSelf) {
      [strongSelf.activityIndicatorView stopAnimating];
    }
  } onError:^(NSError * _Nonnull error) {
    // 최초 광고 할당에 실패하면 호출됩니다.
    // 로딩 화면 등을 구현한 경우, 여기에서 로딩을 종료합니다.
    __strong typeof(self) strongSelf = weakSelf;
    if (strongSelf) {
      [strongSelf.activityIndicatorView stopAnimating];
    }
    // NativeAd2View를 숨기거나, Error UI로 대체할 수 있습니다.
    NSLog(@"Failed to load ad by %@.", error.localizedDescription);
  } onCompleted:^{
    // 더 이상 갱신할 수 있는 광고가 없을 때 호출됩니다.
    // 로딩 화면 등을 구현한 경우, 여기에서 로딩을 종료합니다.
    __strong typeof(self) strongSelf = weakSelf;
    if (strongSelf) {
      [strongSelf.activityIndicatorView stopAnimating];
    }
  }];

  // 광고 할당 및 표시를 자동으로 수행합니다.
  [_viewBinder bind];
}

@end
```

##### 베이스 리워드 금액 표시하기

베이스 리워드를 미리 표시하는 기능이 삭제 되었습니다. 이에 따라 `BuzzAdBenefit.getAvailableFeedBaseReward()`함수도 삭제되어서 관련 코드삭제가 필요합니다.

참고 - 변경 전 코드(BuzzAdBenefit SDK v5)

**Swift**

```swift
BuzzAdBenefit.getAvailableFeedBaseReward(for: YOUR_FEED_UNIT_ID) { [weak self] (reward) in
  guard let self = self else { return }
  if reward > 0 {
    self.nativeToFeedLabel.text = "\(reward) 포인트 받고 더 많은 참여 기회 보기"
  } else {
    self.nativeToFeedLabel.text = "더 많은 참여 기회 보기"
  }
}
```

**Objective-C**

```objectivec
__weak typeof(self) weakSelf = self;
[BuzzAdBenefit getAvailableFeedBaseRewardFor:@"YOUR_FEED_UNIT_ID" onComplete:^(NSInteger reward) {
  __strong typeof(self) strongSelf = weakSelf;
  if (strongSelf) {
    if (reward > 0) {
      strongSelf.nativeToFeedLabel.text = [NSString stringWithFormat:@"%d 포인트 받고 더 많은 참여 기회 보기", reward];
    } else {
      strongSelf.nativeToFeedLabel.text = @"더 많은 참여 기회 보기";
    }
  }
}];
```

### 추가 구현

#### 동영상 광고 리스너 등록하기

Native 지면에서는 동영상 광고가 제공되지 않기 때문에 동영상 광고 리스너는 제거 되었습니다. `BZVNativeAdViewVideoDelegate` protocol이 삭제 되었기 때문에 관련 코드 삭제가 필요합니다.

참고 - 변경 전 코드(BuzzAdBenefit SDK v5)

**Swift**

```swift
import UIKit
import BuzzvilSDK

final class ViewController: UIViewController {
  private let nativeAd2View = BZVNativeAd2View(frame: .zero)
  // ...생략...

  override func viewDidLoad() {
    // ...생략...
    nativeAd2View.videoDelegate = self
  }
}

// MARK: BZVNativeAdViewVideoDelegate
extension ViewController: BZVNativeAdViewVideoDelegate {
  func bzvNativeAdView(_ nativeAdView: BZVNativeAdView, willStartPlayingVideoAd nativeAd: BZVNativeAd) {
    // 비디오 광고의 비디오가 시작하기 직전에 호출됩니다.
  }

  func bzvNativeAdView(_ nativeAdView: BZVNativeAdView, didResumeVideoAd nativeAd: BZVNativeAd) {
    // 비디오 광고의 비디오가 재생되면 호출됩니다.
  }

  func bzvNativeAdView(_ nativeAdView: BZVNativeAdView, willReplayVideoAd nativeAd: BZVNativeAd) {
    // 비디오 광고의 비디오가 리플레이되면 호출됩니다.
  }

  func bzvNativeAdView(_ nativeAdView: BZVNativeAdView, didPauseVideoAd nativeAd: BZVNativeAd) {
    // 비디오 광고의 비디오가 일시정지되면 호출됩니다.
  }

  func bzvNativeAdView(_ nativeAdView: BZVNativeAdView, didFinishPlayingVideoAd nativeAd: BZVNativeAd) {
    // 비디오 광고의 비디오가 종료되면 호출됩니다.
  }
}
```

**Objective-C**

```objectivec
@import BuzzvilSDK;

@interface ViewController () <BZVNativeAdViewVideoDelegate>

@property (nonatomic, strong, readonly) BZVNativeAd2View *nativeAd2View;
// ...생략...

@end

@implementation ViewController

- (void)viewDidLoad {
  // ...생략...
  _nativeAd2View.videoDelegate = self;
}

#pragma mark - BZVNativeAdViewVideoDelegate
- (void)BZVNativeAdView:(BZVNativeAdView *)nativeAdView willStartPlayingVideoAd:(BZVNativeAd *)nativeAd {
  // 비디오 광고의 비디오가 시작하기 직전에 호출됩니다.
}

- (void)BZVNativeAdView:(BZVNativeAdView *)nativeAdView didResumeVideoAd:(BZVNativeAd *)nativeAd {
  // 비디오 광고의 비디오가 재생되면 호출됩니다.
}

- (void)BZVNativeAdView:(BZVNativeAdView *)nativeAdView willReplayVideoAd:(BZVNativeAd *)nativeAd {
  // 비디오 광고의 비디오가 리플레이되면 호출됩니다.
}

- (void)BZVNativeAdView:(BZVNativeAdView *)nativeAdView didPauseVideoAd:(BZVNativeAd *)nativeAd {
  // 비디오 광고의 비디오가 일시정지되면 호출됩니다.
}

- (void)BZVNativeAdView:(BZVNativeAdView *)nativeAdView didFinishPlayingVideoAd:(BZVNativeAd *)nativeAd {
  // 비디오 광고의 비디오가 종료되면 호출됩니다.
}

@end
```

#### 광고 이벤트 리스너 등록하기

`BZVNativeAd2ViewBinder`를 통해 광고 이벤트를 받을 수 있던 부분이 `BuzzNative` 객체를 통해 받도록 변경 되었습니다. 이에 따라 코드 업데이트가 필요합니다.

**Swift**

```swift
final class ViewController: UIViewController {
  // ...생략...

  override func viewDidLoad() {
    // ...생략...

    // Native 광고 이벤트 처리를 위한 closure를 등록하고 각 이벤트에 따라 필요한 기능을 구현합니다.
    // Warning: retain cycle 방지를 위해 closure 내에서 반드시 weak self를 사용해주세요.
    native.subscribeAdEvents(onImpressed: { [weak self] nativeAd in
      // Native 광고가 유저에게 노출되었을 때 호출됩니다.
    }, onClicked: { [weak self] nativeAd in
      // 유저가 Native 광고를 클릭했을 때 호출됩니다.
    }, onRewardRequested: { [weak self] nativeAd in
      // 리워드 적립 요청시에 호출됩니다.
    }, onRewarded: { [weak self] nativeAd, rewardResult in
      // 리워드 적립 결과를 수신했을 때 호출됩니다.
    }, onParticipated: { [weak self] nativeAd in
      // 광고 참여가 완료되었을 때 호출됩니다.
    })

    // ...생략...
  }
}
```

**Objective-C**

```objectivec
@implementation ViewController

- (void)viewDidLoad {
  // ...생략...
  
  // Native 광고 이벤트 처리를 위한 closure를 등록하고 각 이벤트에 따라 필요한 기능을 구현합니다.
  // Warning: retain cycle 방지를 위해 closure 내에서 반드시 weak self를 사용해주세요.
  __weak typeof(self) weakSelf = self;
  [_native subscribeAdEventsOnImpressed:^(BuzzNativeAd * _Nonnull nativeAd) {
    __strong typeof(self) strongSelf = weakSelf;
    // Native 광고가 유저에게 노출되었을 때 호출됩니다.
  } onClicked:^(BuzzNativeAd * _Nonnull nativeAd) {
    __strong typeof(self) strongSelf = weakSelf;
    // 유저가 Native 광고를 클릭했을 때 호출됩니다.
  } onRewardRequested:^(BuzzNativeAd * _Nonnull nativeAd) {
    __strong typeof(self) strongSelf = weakSelf;
    // 리워드 적립 요청시에 호출됩니다.
  } onRewarded:^(BuzzNativeAd * _Nonnull nativeAd, BuzzRewardResult rewardResult) {
    __strong typeof(self) strongSelf = weakSelf;
    // 리워드 적립 결과를 수신했을 때 호출됩니다.
  } onParticipated:^(BuzzNativeAd * _Nonnull nativeAd) {
    __strong typeof(self) strongSelf = weakSelf;
    // 광고 참여가 완료되었을 때 호출됩니다.
  }];

  // ...생략...
}

@end
```

참고 - 변경 전 코드(BuzzAdBenefit SDK v5)

**Swift**

```swift
final class ViewController: UIViewController {
  // ...생략...

  override func viewDidLoad() {
    // ...생략...

    // Native 광고 이벤트 처리를 위한 closure를 등록하고 각 이벤트에 따라 필요한 기능을 구현합니다.
    // 로그 기록, 단순 알림 외에 다른 동작을 추가하는 것을 권장하지 않습니다. 자동 갱신 등 네이티브 2.0의 기능과 직접 구현한 동작이 충돌할 수 있습니다.
    // Warning: 반드시 bind 함수를 호출하기 전에 호출해야 해야합니다.
    // Warning: retain cycle 방지를 위해 closure 내에서 반드시 weak self를 사용해주세요.
    viewBinder.subscribeAdEvents(onImpressed: { [weak self] nativeAd2 in
      // Native 광고가 유저에게 노출되었을 때 호출됩니다.
    }, onClicked: { [weak self] nativeAd2 in
      // 유저가 Native 광고를 클릭했을 때 호출됩니다.
    }, onRewardRequested: { [weak self] nativeAd2 in
      // 리워드 적립 요청시에 호출됩니다.
    }, onRewarded: { [weak self] nativeAd2, rewardResult in
      // 리워드 적립 결과를 수신했을 때 호출됩니다.
    }, onParticipated: { [weak self] nativeAd2 in
      // 광고 참여가 완료되었을 때 호출됩니다.
    })

    viewBinder.bind()
  }
}
```

**Objective-C**

```objectivec
@implementation ViewController

- (void)viewDidLoad {
  // ...생략...
  
  // Native 광고 이벤트 처리를 위한 closure를 등록하고 각 이벤트에 따라 필요한 기능을 구현합니다.
  // 로그 기록, 단순 알림 외에 다른 동작을 추가하는 것을 권장하지 않습니다. 자동 갱신 등 네이티브 2.0의 기능과 직접 구현한 동작이 충돌할 수 있습니다.
  // Warning: 반드시 bind 함수를 호출하기 전에 호출해야 해야합니다.
  // Warning: retain cycle 방지를 위해 closure 내에서 반드시 weak self를 사용해주세요.
  __weak typeof(self) weakSelf = self;
  [_viewBinder subscribeAdEventsOnImpressed:^(BZVNativeAd2 * _Nonnull nativeAd2) {
    __strong typeof(self) strongSelf = weakSelf;
    // Native 광고가 유저에게 노출되었을 때 호출됩니다.
  } onClicked:^(BZVNativeAd2 * _Nonnull nativeAd2) {
    __strong typeof(self) strongSelf = weakSelf;
    // 유저가 Native 광고를 클릭했을 때 호출됩니다.
  } onRewardRequested:^(BZVNativeAd2 * _Nonnull nativeAd2) {
    __strong typeof(self) strongSelf = weakSelf;
    // 리워드 적립 요청시에 호출됩니다.
  } onRewarded:^(BZVNativeAd2 * _Nonnull nativeAd2, BZVRewardResult rewardResult) {
    __strong typeof(self) strongSelf = weakSelf;
    // 리워드 적립 결과를 수신했을 때 호출됩니다.
  } onParticipated:^(BZVNativeAd2 * _Nonnull nativeAd2) {
    __strong typeof(self) strongSelf = weakSelf;
    // 광고 참여가 완료되었을 때 호출됩니다.
  }];

  [_viewBinder bind];
}

@end
```

#### 리워드 적립 결과 (`BZVRewardResult`)

`BZVRewardResult`에서 `BuzzRewardResult` 로 클래스 명이 변경 되었습니다. [리워드 적립 결과(`BuzzRewardResult`) 종류](https://docs.buzzvil.com/docs/buzzbenefit-ios/v6/native#%EB%A6%AC%EC%9B%8C%EB%93%9C-%EC%A0%81%EB%A6%BD-%EA%B2%B0%EA%B3%BCbuzzrewardresult-%EC%A2%85%EB%A5%98)를 참고하세요.

#### 캐러셀 구현하기

##### 캐러셀의 기본 기능 구현하기

###### 1 단계. 광고 할당 받기

기존에 사용하고있던 class 및 함수들이 변경 되었습니다. 아래 표를 참고하여 코드를 업데이트 해 주세요

| AS-IS                        | TO-BE                    |
| ---------------------------- | ------------------------ |
| `BZVNativeAd2Pool`           | `BuzzNativeGroup`        |
| `BZVNativeAd2Pool.loadAds()` | `BuzzNativeGroup.load()` |
| `completionHandler`          | `onSuccess`              |
| `errorHandler`               | `onFailure`              |

**Swift**

```swift
import UIKit
import BuzzvilSDK

final class CarouselViewController: UIViewController {
  private let unitId = "YOUR_UNIT_ID"
  
  // 최대 10개의 광고를 요청할 수 있습니다.
  private let adRequestCount = 5

  // 실제 할당받은 광고의 개수입니다. 
  // 이 값은 collectionView datasource의 collectionView(_:numberOfItemsInSection:) 함수의 return 값으로 사용합니다.
  private var loadedAdCount = 0

  // 광고 중복 할당을 막기 위해 하나의 캐러셀에 하나의 BuzzNativeGroup 인스턴스를 생성하여 사용합니다.
  private lazy var nativeGroup = BuzzNativeGroup(unitId: unitId)

  override func viewDidLoad() {
    super.viewDidLoad()
    setupCarousel()
  }

  private func setupCarousel() {
    // BuzzNativeGroup에 광고 할당을 요청합니다.
    nativeGroup.load(
      count: adRequestCount,
      onSuccess: { [weak self] adCount in
        // 실제로 할당받은 광고의 개수(count)를 업데이트합니다.
        self?.loadedAdCount = adCount
      },
      onFailure: { [weak self] error in
        // 광고 할당 실패 시 발생하는 NSError 오류 코드에 대한 자세한 내용은 오류 코드가 나타납니다 토픽을 참고하세요.
      }
    )
  }
}
```

**Objective-C**

```objectivec
@import BuzzvilSDK;

static NSString * const kUnitId = @"YOUR_UNIT_ID";

@interface CarouselViewController ()

// 최대 10개의 광고를 요청할 수 있습니다.
@property (nonatomic, assign, readonly) NSInteger adRequestCount;

// 실제 할당받은 광고의 개수입니다. 
// 이 값은 collectionView datasource의 collectionView(_:numberOfItemsInSection:) 함수의 return 값으로 사용합니다.
@property (nonatomic, assign, readwrite) NSInteger loadedAdCount;

// 광고 중복 할당을 막기 위해 하나의 캐러셀에 하나의 BuzzNativeGroup 인스턴스를 생성하여 사용합니다.
@property (nonatomic, strong, readonly) BuzzNativeGroup *nativeGroup;

@end

@implementation CarouselViewController

- (void)viewDidLoad {
  [super viewDidLoad];

  _adRequestCount = 5;
  _loadedAdCount = 0;
  _nativeGroup = [[BuzzNativeGroup alloc] initWithUnitId:kUnitId];

  [self setupCarousel];
}

- (void)setupCarousel {
  __weak typeof(self) weakSelf = self;
 // BuzzNativeGroup에 광고 할당을 요청합니다.
  [self.nativeGroup loadWithCount:self.adRequestCount onSuccess:^(NSInteger count) {
    __strong typeof(self) strongSelf = weakSelf;
    if (strongSelf) {
      // 실제로 할당받은 광고의 개수(count)를 업데이트합니다.
      strongSelf.loadedAdCount = count;
    }
  } onFailure:^(NSError * _Nonnull error) {
    // 광고 할당 실패 시 발생하는 NSError 오류 코드에 대한 자세한 내용은 오류 코드가 나타납니다 토픽을 참고하세요.
  }];
}

@end
```

참고 - 변경 전 코드(BuzzAdBenefit SDK v5)

**Swift**

```swift
import UIKit
import BuzzvilSDK

final class CarouselViewController: UIViewController {
  private let unitID = "YOUR_UNIT_ID"
  
  // 최대 10개의 광고를 요청할 수 있습니다.
  private let adRequestCount = 5

  // 실제 할당받은 광고의 개수입니다. 
  // 이 값은 collectionView datasource의 collectionView(_:numberOfItemsInSection:) 함수의 return 값으로 사용합니다.
  private var loadedAdCount = 0

  // 광고 중복 할당을 막기 위해 하나의 캐러셀에 하나의 NativeAd2Pool 인스턴스를 생성하여 사용합니다.
  private lazy var pool = BZVNativeAd2Pool(unitId: unitId)

  override func viewDidLoad() {
    super.viewDidLoad()
    setupCarousel()
  }

  private func setupCarousel() {
    // BZVNativeAd2Pool에 광고 할당을 요청합니다.
    pool.loadAds(count: adRequestCount) { [weak self] adCount in
      // 실제로 할당받은 광고의 개수(adCount)를 업데이트합니다.
      self?.loadedAdCount = adCount
    } errorHandler: { [weak self] error in
      // 광고 할당 실패 시 발생하는 NSError 오류 코드에 대한 자세한 내용은 오류 코드가 나타납니다 토픽을 참고하세요.
    }
  }
}
```

**Objective-C**

```objectivec
@import BuzzvilSDK;

static NSString * const kUnitId = @"YOUR_UNIT_ID";

@interface CarouselViewController ()

// 최대 10개의 광고를 요청할 수 있습니다.
@property (nonatomic, assign, readonly) NSInteger adRequestCount;

// 실제 할당받은 광고의 개수입니다. 
// 이 값은 collectionView datasource의 collectionView(_:numberOfItemsInSection:) 함수의 return 값으로 사용합니다.
@property (nonatomic, assign, readwrite) NSInteger loadedAdCount;

// 광고 중복 할당을 막기 위해 하나의 캐러셀에 하나의 NativeAd2Pool 인스턴스를 생성하여 사용합니다.
@property (nonatomic, strong, readonly) BZVNativeAd2Pool *pool;

@end

@implementation CarouselViewController

- (void)viewDidLoad {
  [super viewDidLoad];

  _adRequestCount = 5;
  _loadedAdCount = 0;
  _pool = [[BZVNativeAd2Pool alloc] initWithUnitId:kUnitId];  

  [self setupCarousel];
}

- (void)setupCarousel {
  __weak typeof(self) weakSelf = self;
  // BZVNativeAd2Pool에 광고 할당을 요청합니다.
  [self.pool loadAdsWithCount:self.adRequestCount completionHandler:^(NSInteger adCount) {
    __strong typeof(self) strongSelf = weakSelf;
    if (strongSelf) {
      // 실제로 할당받은 광고의 개수(adCount)를 업데이트합니다.
      strongSelf.loadedAdCount = adCount;
    }
  } errorHandler:^(NSError * _Nonnull error) {
    // 광고 할당 실패 시 발생하는 NSError 오류 코드에 대한 자세한 내용은 오류 코드가 나타납니다 토픽을 참고하세요.
  }];
}

@end
```

###### 2단계. UICollectionViewCell 구현하기

기존에 구현되어있던 `UICollectionViewCell`에서 `setPoool()` 함수를 통해 구현되어 있던 부분을 `bind(with native: BuzzNative)`로 바꿔서 `BuzzNative` 객체를 UIcollectionUIViewCell에 전달하여 필요한 코드를 추가하여야 합니다.

**Swift**

```swift
final class CarouselCell: UICollectionViewCell {
  // ...

  private lazy var viewBinder = BuzzNativeViewBinder.Builder()
    .nativeAdView(nativeAdView)
    .mediaView(mediaView)
    .iconImageView(iconImageView)
    .titleLabel(titleLabel)
    .descriptionLabel(descriptionLabel)
    .ctaView(ctaView)
    .build()
  
  // ...

  override func prepareForReuse() {
    super.prepareForReuse()
    // prepareForReuse 내에서 unbind를 반드시 호출하여 cell을 재사용할 때 문제가 발생하지 않게 합니다.
    viewBinder.unbind()
  }

  // collectionView의 collectionView(_:cellForItemAt:) 시점에 호출합니다.
  func bind(with native: BuzzNative) {
   // bind()를 호출하면 할당된 광고 표시 및 갱신이 자동으로 수행됩니다.
    viewBinder.bind(native)
  }
}
```

**Objective-C**

```objectivec
@interface CarouselCell : UICollectionViewCell

- (void)bind:(BuzzNativeAd *)native;

@end

@interface CarouselCell ()

// ...
@property (nonatomic, strong, readonly) BuzzNativeViewBinder *viewBinder;

@end

@implementation CarouselCell

// ...

- (void)prepareForReuse {
  [super prepareForReuse];
  // prepareForReuse 내에서 unbind를 반드시 호출하여 cell을 재사용할 때 문제가 발생하지 않게 합니다.
  [_viewBinder unbind];
}

// collectionView의 collectionView(_:cellForItemAt:) 시점에 호출합니다.
- (void)bind {
  // bind()를 호출하면 할당된 광고 표시 및 갱신이 자동으로 수행됩니다.
  [_viewBinder bindWithNative:native];
}

@end
```

참고 - 변경 전 코드(BuzzAdBenefit SDK v5)

**Swift**

```swift
final class CarouselCell: UICollectionViewCell {
  // ...

  private lazy var viewBinder = BZVNativeAd2ViewBinder
    .Builder(unitId: "YOUR_NATIVE_UNIT_ID")
    .nativeAd2View(nativeAd2View)
    .mediaView(mediaView)
    .iconImageView(iconImageView)
    .titleLabel(titleLabel)
    .descriptionLabel(descriptionLabel)
    .ctaView(ctaView)
    .build()
  
  // ...

  override func prepareForReuse() {
    super.prepareForReuse()
    // prepareForReuse 내에서 unbind를 반드시 호출하여 cell을 재사용할 때 문제가 발생하지 않게 합니다.
    viewBinder.unbind()
  }

  // collectionView의 collectionView(_:cellForItemAt:) 시점에 호출합니다.
  func setPool(with pool: BZVNativeAd2Pool, for adKey: Int) {
    // 해당 index(adKey)에 해당하는 NativeAd2ViewBinder가 NativeAd2Pool을 사용하도록 합니다.
    viewBinder.setPool(pool, at: adKey)
  }

  // collectionView의 collectionView(_:cellForItemAt:) 시점에 호출합니다.
  func bind() {
    // NativeAd2ViewBinder의 bind()를 호출하면 광고 할당 및 갱신이 자동으로 수행됩니다.
    viewBinder.bind()
  }
}
```

**Objective-C**

```objectivec
@interface CarouselCell : UICollectionViewCell

- (void)setPool:(BZVNativeAd2Pool *)pool forAdKey:(NSInteger)adKey;
- (void)bind;

@end

@interface CarouselCell ()

// ...
@property (nonatomic, strong, readonly) BZVNativeAd2ViewBinder *viewBinder;

@end

@implementation CarouselCell

// ...

- (void)prepareForReuse {
  [super prepareForReuse];
  // prepareForReuse 내에서 unbind를 반드시 호출하여 cell을 재사용할 때 문제가 발생하지 않게 합니다.
  [_viewBinder unbind];
}

// collectionView의 collectionView(_:cellForItemAt:) 시점에 호출합니다.
- (void)setPool:(BZVNativeAd2Pool *)pool forAdKey:(NSInteger)adKey {
  // 해당 index(adKey)에 해당하는 NativeAd2ViewBinder가 NativeAd2Pool을 사용하도록 합니다.
  [_viewBinder setPool:pool at:adKey];
}

// collectionView의 collectionView(_:cellForItemAt:) 시점에 호출합니다.
- (void)bind {
  // NativeAd2ViewBinder의 bind()를 호출하면 광고 할당 및 갱신이 자동으로 수행됩니다.
  [_viewBinder bind];
}

@end
```

###### 베네핏허브 진입 슬라이드

기능이 삭제되어 `BZVFeedPromotionView`, `BZVFeedPromotionViewBinder`가 삭제되었습니다. 관련 코드에서 해당 코드들을 제거 해 주세요. 이전 가이드에 있던 `FeedPromitionCell`도 제거 해야 합니다.

###### 베네핏허브 진입

베네핏허브 진입점으로써 활용되고 있던 `BZVFeedEntryView` 클래스가 삭제 되었습니다. 베네핏허브 진입을 위한 코드로 변경이 필요 합니다. 아래의 코드로 업데이트 해 주세요.

**Swift**

```swift
let yourViewController = UIViewController()
let benefitHub = BuzzBenefitHub()
benefitHub.show(on: yourViewController)
```

**Objective C**

```objectivec
UIViewController *yourViewController = [[UIViewController alloc] init];
BuzzBenefitHub *benefitHub = [[BuzzBenefitHub alloc] init];
[benefitHub showOn:yourViewController];
```

참고 - 변경 전 코드(BuzzAdBenefit SDK v5)

**Swift**

```swift
import UIKit
import BuzzvilSDK

final class CarouselFeedEntryView: BZVFeedEntryView {
  private lazy var button: UIButton = {
    let button = UIButton(type: .system)
    button.setTitle("포인트 더 받으러 가기", for: .normal)
    button.tintColor = .systemBlue
    return button
  }()
  
  override init(frame: CGRect) {
    super.init(frame: frame)
    setupView()
    setupLayout()
  }
  
  required init?(coder: NSCoder) {
    fatalError()
  }
  
  private func setupView() {
    addSubview(button)
    clickableViews = [button]
  }
  
  private func setupLayout() {
    button.translatesAutoresizingMaskIntoConstraints = false
    NSLayoutConstraint.activate([
      button.topAnchor.constraint(equalTo: topAnchor),
      button.leadingAnchor.constraint(equalTo: leadingAnchor),
      button.trailingAnchor.constraint(equalTo: trailingAnchor),
      button.bottomAnchor.constraint(equalTo: bottomAnchor),
    ])
  }
}
```

**Objective-C**

```objectivec
@import UIKit;
@import BuzzvilSDK;

@interface CarouselFeedEntryView: BZVFeedEntryView

@end

@interface CarouselFeedEntryView ()

@property (nonatomic, strong, readonly) UIButton *button;

@end

@implementation CustomFeedEntryView

- (instancetype)initWithFrame:(CGRect)frame {
  if (self = [super initWithFrame:frame]) {
    [self setupView];
    [self setupLayout];
  }
  return self;
}

- (void)setupView {
  _button = [[UIButton alloc] initWithFrame:CGRectZero];
  [_button setTitle:@"포인트 더 받으러 가기" forState:UIControlStateNormal];
  [_button setTitleColor:[UIColor systemBlueColor] forState:UIControlStateNormal];
  [self addSubview:_button];
  self.clickableViews = @[self.button];
}

- (void)setupLayout {
  _button.translatesAutoresizingMaskIntoConstraints = NO;
  [NSLayoutConstraint activateConstraints:@[
    [_button.topAnchor constraintEqualToAnchor:self.topAnchor],
    [_button.leadingAnchor constraintEqualToAnchor:self.leadingAnchor],
    [_button.trailingAnchor constraintEqualToAnchor:self.trailingAnchor],
    [_button.bottomAnchor constraintEqualToAnchor:self.bottomAnchor],
  ]];
}

@end
```

##### 캐러셀의 부가 기능 구현하기

###### 로딩 화면 구현하기

분리되어있던 함수가 UICollectionViewCell에서 만든 `bind(with native: BuzzNative)` 함수 안으로 이동 되었습니다.

**Swift**

```swift
final class CarouselCell: UICollectionViewCell {
  // ...
  
  private lazy var activityIndicatorView: UIActivityIndicatorView = {
    let indicator = UIActivityIndicatorView(frame: .zero)
    indicator.hidesWhenStopped = true
    return indicator
  }()
  
  override init(frame: CGRect) {
    super.init(frame: frame)
    setupView()
    setupLayout()
  }
  
  private func setupView() {
    // ...
    contentView.addSubview(activityIndicatorView)
  }
  
  private func setupLayout() {
    // ...
    
    activityIndicatorView.translatesAutoresizingMaskIntoConstraints = false
    NSLayoutConstraint.activate([
      activityIndicatorView.centerXAnchor.constraint(equalTo: centerXAnchor),
      activityIndicatorView.centerYAnchor.constraint(equalTo: centerYAnchor),
    ])
  }
  
  func bind(with native: BuzzNative) {
    native.subscribeRefreshEvents(
      onRequest: { [weak self] in
        self?.activityIndicatorView.startAnimating()
        self?.nativeAdView.alpha = 0.5
      },
      onSuccess: { [weak self] _ in
        self?.activityIndicatorView.stopAnimating()
        self?.nativeAdView.alpha = 1
      },
      onFailure: { [weak self] error in
        self?.activityIndicatorView.stopAnimating()
        self?.nativeAdView.alpha = 1
      },
    )

    viewBinder.bind(native: native)
  }
}

extension CarouselViewController: UICollectionViewDataSource {
  func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    // ...
    cell.bind(with: native)
    return cell
  }
}
```

**Objective-C**

```objectivec
@interface CarouselCell ()

// ...
@property (nonatomic, strong, readonly) UIActivityIndicatorView *activityIndicatorView;

@end

@implementation CarouselCell

- (instancetype)initWithFrame:(CGRect)frame {
  self = [super initWithFrame:frame];
  if (self) {
    [self setupView];
    [self setupLayout];
  }
  return self;
}

- (void)setupView {
  // ...

  _activityIndicatorView = [[UIActivityIndicatorView alloc] initWithFrame:CGRectZero];
  _activityIndicatorView.hidesWhenStopped = YES;
  [self.contentView addSubview:_activityIndicatorView];
}

- (void)setupLayout {
  // ...
  
  _activityIndicatorView.translatesAutoresizingMaskIntoConstraints = NO;
  [NSLayoutConstraint activateConstraints:@[
    [_activityIndicatorView.centerXAnchor constraintEqualToAnchor:self.centerXAnchor],
    [_activityIndicatorView.centerYAnchor constraintEqualToAnchor:self.centerYAnchor],
  ]];
}

- (void)bindWithNative:(BuzzNative *)native {
  __weak typeof(self) weakSelf = self;
  [_native subscribeRefreshEventsOnRequest:^{
    __strong typeof(self) strongSelf = weakSelf;
    if (strongSelf) {
      [strongSelf.activityIndicatorView startAnimating];
      strongSelf.nativeAdView.alpha = 0.5;
    }
  } onSuccess:^{
    __strong typeof(self) strongSelf = weakSelf;
    if (strongSelf) {
      [strongSelf.activityIndicatorView stopAnimating];
      strongSelf.nativeAdView.alpha = 1;
    }
  } onFailure:^(NSError * _Nonnull error) {
    __strong typeof(self) strongSelf = weakSelf;
    if (strongSelf) {
      [strongSelf.activityIndicatorView stopAnimating];
      strongSelf.nativeAdView.alpha = 1;
    }
  }];
}

@end

@implementation CarouselViewController

// ...

#pragma mark - UICollectionViewDataSource

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
  // ...
  [cell bindWithNative:native];
  return cell;
}

@end
```

참고 - 변경 전 코드(BuzzAdBenefit SDK v5)

**Swift**

```swift
final class CarouselCell: UICollectionViewCell {
  // ...
  
  private lazy var activityIndicatorView: UIActivityIndicatorView = {
    let indicator = UIActivityIndicatorView(frame: .zero)
    indicator.hidesWhenStopped = true
    return indicator
  }()
  
  override init(frame: CGRect) {
    super.init(frame: frame)
    setupView()
    setupLayout()
  }
  
  private func setupView() {
    // ...
    contentView.addSubview(activityIndicatorView)
  }
  
  private func setupLayout() {
    // ...
    
    activityIndicatorView.translatesAutoresizingMaskIntoConstraints = false
    NSLayoutConstraint.activate([
      activityIndicatorView.centerXAnchor.constraint(equalTo: centerXAnchor),
      activityIndicatorView.centerYAnchor.constraint(equalTo: centerYAnchor),
    ])
  }
  
  func setupLoading() {
    viewBinder.subscribeEvents(onRequest: { [weak self] in
      self?.activityIndicatorView.startAnimating()
      self?.nativeAd2View.alpha = 0.5
    }, onNext: { [weak self] _ in
      self?.activityIndicatorView.stopAnimating()
      self?.nativeAd2View.alpha = 1
    }, onError: { [weak self] in
      self?.activityIndicatorView.stopAnimating()
      self?.nativeAd2View.alpha = 1
      print("error: \($0)")
    }, onCompleted: { [weak self] in
      self?.activityIndicatorView.stopAnimating()
      self?.nativeAd2View.alpha = 1
      print("completed")
    })
  }
}

extension CarouselViewController: UICollectionViewDataSource {
  func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    // ...
    cell.setupLoading()
    cell.setPool(with: pool, for: indexPath.item)
    cell.bind()
    return cell
  }
}
```

**Objective-C**

```objectivec
@interface CarouselCell : UICollectionViewCell

// ...
- (void)setupLoading

@end

@interface CarouselCell ()

// ...
@property (nonatomic, strong, readonly) UIActivityIndicatorView *activityIndicatorView;

@end

@implementation CarouselCell

- (instancetype)initWithFrame:(CGRect)frame {
  self = [super initWithFrame:frame];
  if (self) {
    [self setupView];
    [self setupLayout];
  }
  return self;
}

- (void)setupView {
  // ...

  _activityIndicatorView = [[UIActivityIndicatorView alloc] initWithFrame:CGRectZero];
  _activityIndicatorView.hidesWhenStopped = YES;
  [self.contentView addSubview:_activityIndicatorView];
}

- (void)setupLayout {
  // ...
  
  _activityIndicatorView.translatesAutoresizingMaskIntoConstraints = NO;
  [NSLayoutConstraint activateConstraints:@[
    [_activityIndicatorView.centerXAnchor constraintEqualToAnchor:self.centerXAnchor],
    [_activityIndicatorView.centerYAnchor constraintEqualToAnchor:self.centerYAnchor],
  ]];
}

- (void)setupLoading {
  __weak typeof(self) weakSelf = self;
  [_viewBinder subscribeEventsOnRequest:^{
    __strong typeof(self) strongSelf = weakSelf;
    if (strongSelf) {
      [strongSelf.activityIndicatorView startAnimating];
      strongSelf.nativeAd2View.alpha = 0.5;
    }
  } onNext:^(BZVNativeAd2 * _Nonnull ad) {
    __strong typeof(self) strongSelf = weakSelf;
    if (strongSelf) {
      [strongSelf.activityIndicatorView stopAnimating];
      strongSelf.nativeAd2View.alpha = 1;
    }
  } onError:^(NSError * _Nonnull error) {
    __strong typeof(self) strongSelf = weakSelf;
    if (strongSelf) {
      [strongSelf.activityIndicatorView stopAnimating];
      strongSelf.nativeAd2View.alpha = 1;
      NSLog(@"error: %@", error);
    }
  } onCompleted:^{
    __strong typeof(self) strongSelf = weakSelf;
    if (strongSelf) {
      [strongSelf.activityIndicatorView stopAnimating];
      strongSelf.nativeAd2View.alpha = 1;
      NSLog(@"completed");
    }
  }];
}

@end

@implementation CarouselViewController

// ...

#pragma mark - UICollectionViewDataSource

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
  // ...
  [cell setupLoading];
  [cell setPool:_pool forIndex:indexPath.item];
  [cell bind];
  return cell;
}

@end
```

###### 광고 이벤트 리스너 등록하기

함수 변경 ! 위치도 변경 ! bind() 안에 있음 분리되어있던 함수가 UICollectionViewCell에서 만든 `bind(with native: BuzzNative)` 함수 안으로 이동 되었습니다. 기존에 사용하던 `BZVNativeAd2ViewBinder` class 가 아닌 `BuzzNative` 객체를 통해서 등록하도록 변경 되었습니다.

**Swift**

```swift
final class CarouselCell: UICollectionViewCell {
  // ...
  
  func bind(with native: BuzzNative) {
    // ...

    native.subscribeAdEvents(
      onImpressed: { [weak self] in
        print("impressed: \($0.title)")
      }, 
      onClicked: { [weak self] in
        print("clicked: \($0.title)")
      }, 
      onRewardRequested: { [weak self] in
        print("requested reward: \($0.title)")
      }, 
      onRewarded: { [weak self] in
        print("received reward result: \($0.title), \($1)")
      }, 
      onParticipated: { [weak self] in
        print("participated: \($0.title)")
      }
    )

    // ...
  }
}

extension CarouselViewController: UICollectionViewDataSource {
  func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    // ...
    cell.bind(with: native)
    return cell
  }
}
```

**Objective-C**

```objectivec
@implementation CarouselCell

// ...

- (void)bindWithNative:(BuzzNative *)native {
  __weak typeof(self) weakSelf = self;
  [native subscribeAdEventsOnImpressed:^(BuzzNativeAd * _Nonnull ad) {
    __strong typeof(self) strongSelf = weakSelf;
    if (strongSelf) {
      NSLog(@"impressed: %@", ad.title);
    }
  } onClicked:^(BuzzNativeAd * _Nonnull ad) {
    __strong typeof(self) strongSelf = weakSelf;
    if (strongSelf) {
      NSLog(@"clicked: %@", ad.title);
    }
  } onRewardRequested:^(BuzzNativeAd * _Nonnull ad) {
    __strong typeof(self) strongSelf = weakSelf;
    if (strongSelf) {
      NSLog(@"requested reward: %@", ad.title);
    }
  } onRewarded:^(BuzzNativeAd * _Nonnull ad, BuzzRewardResult result) {
    __strong typeof(self) strongSelf = weakSelf;
    if (strongSelf) {
      NSLog(@"received reward result: %@", ad.title);
    }
  } onParticipated:^(BuzzNativeAd * _Nonnull ad) {
    __strong typeof(self) strongSelf = weakSelf;
    if (strongSelf) {
      NSLog(@"participated: %@", ad.title);
    }
  }];
}

@end

@implementation CarouselViewController

// ...

#pragma mark - UICollectionViewDataSource

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
  // ...
  [cell bindWithNative:native];
  return cell;
}

@end
```

참고 - 변경 전 코드(BuzzAdBenefit SDK v5)

**Swift**

```swift
final class CarouselCell: UICollectionViewCell {
  // ...
  
  func setupEventListeners() {
    viewBinder.subscribeAdEvents(onImpressed: { [weak self] in
      print("impressed: \($0.title)")
    }, onClicked: { [weak self] in
      print("clicked: \($0.title)")
    }, onRewardRequested: { [weak self] in
      print("requested reward: \($0.title)")
    }, onRewarded: { [weak self] in
      print("received reward result: \($0.title), \($1)")
    }, onParticipated: { [weak self] in
      print("participated: \($0.title)")
    })
  }
}

extension CarouselViewController: UICollectionViewDataSource {
  func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    // ...
    cell.setupEventListeners()
    cell.setPool(with: pool, for: indexPath.item)
    cell.bind()
    return cell
  }
}
```

**Objective-C**

```objectivec
@interface CarouselCell : UICollectionViewCell

// ...
- (void)setupEventListeners;

@end

@implementation CarouselCell

// ...

- (void)setupEventListeners {
  __weak typeof(self) weakSelf = self;
  [_viewBinder subscribeAdEventsOnImpressed:^(BZVNativeAd2 * _Nonnull ad) {
    __strong typeof(self) strongSelf = weakSelf;
    if (strongSelf) {
      NSLog(@"impressed: %@", ad.title);
    }
  } onClicked:^(BZVNativeAd2 * _Nonnull ad) {
    __strong typeof(self) strongSelf = weakSelf;
    if (strongSelf) {
      NSLog(@"clicked: %@", ad.title);
    }
  } onRewardRequested:^(BZVNativeAd2 * _Nonnull ad) {
    __strong typeof(self) strongSelf = weakSelf;
    if (strongSelf) {
      NSLog(@"requested reward: %@", ad.title);
    }
  } onRewarded:^(BZVNativeAd2 * _Nonnull ad, BZVRewardResult result) {
    __strong typeof(self) strongSelf = weakSelf;
    if (strongSelf) {
      NSLog(@"received reward result: %@", ad.title);
    }
  } onParticipated:^(BZVNativeAd2 * _Nonnull ad) {
    __strong typeof(self) strongSelf = weakSelf;
    if (strongSelf) {
      NSLog(@"participated: %@", ad.title);
    }
  }];
}

@end

@implementation CarouselViewController

// ...

#pragma mark - UICollectionViewDataSource

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
  // ...
  [cell setupEventListeners];
  [cell setPool:_pool forIndex:indexPath.item];
  [cell bind];
  return cell;
}

@end
```

## 인터스티셜(Interstitial)

### 연동

#### 1 단계. 준비하기

변경 사항이 없습니다.

#### 2 단계. 광고 할당 및 표시하기

기존에 사용하던 Class 의 이름 및 프로토콜이 변경 되었습니다. 아래를 참고하시어 코드를 업데이트 해 주세요.

기존 Interstitial 객체 `BZVBuzzAdInterstitial` -> `BuzzInterstitial` 변경 `BuzzInterstitial`의 초기화이 방식 변경 되었습니다. 아래의 코드를 참고하여 업데이트 해 주세요. 기존 Delegate protocol `BZVBuzzAdInterstitialDelegate` -> \~BuzzInterstitialDelegate\` 변경

**Swift**

```swift
import UIKit
import BuzzvilSDK

final class ViewController: UIViewController, BuzzInterstitialDelegate {
  let buzzAdInterstitial = BuzzInterstitial(unitId: "YOUR_INTERSTITIAL_UNIT_ID", type: .dialog)

  override func viewDidLoad() {
    super.viewDidLoad()

    buzzAdInterstitial.delegate = self
    buzzAdInterstitial.load()
  }
}
extension ViewController: BuzzInterstitialDelegate {
  func BuzzInterstitialDidLoadAd(_ interstitial: BuzzInterstitial) {
    // 할당된 광고가 있으면 호출됩니다.
    // Interstitial 광고를 화면에 표시합니다.
    interstitial.present(on: self)
  }
  
  func BuzzInterstitialDidFail(toLoadAd interstitial: BuzzInterstitial, withError error: Error) {
    // 할당된 광고가 없으면 호출됩니다.
  }
  
  func BuzzInterstitialDidDismiss(_ viewController: UIViewController) {
    // Interstitial 지면이 종료되면 호출됩니다.
    // 필요에 따라 추가 기능을 구현하세요.
  }
}
```

**Objective-C**

```objectivec
@import BuzzvilSDK;

@interface ViewController () <BuzzInterstitialDelegate>

@property (nonatomic, strong, readonly) BuzzInterstitial *buzzAdInterstitial;

@end

@implementation ViewController

- (void)viewDidLoad {
  [super viewDidLoad];

  _buzzAdInterstitial = [[BuzzInterstitial alloc] initWithUnitId:@"YOUR_INTERSTITIAL_UNIT_ID" type:BuzzInterstitialTypeDialog];
  _buzzAdInterstitial.delegate = self;
  [_buzzAdInterstitial load];
}

#pragma mark - BuzzInterstitialDelegate
- (void)BuzzInterstitialDidLoadAd:(BuzzInterstitial *)interstitial {
  // 할당된 광고가 있으면 호출됩니다.
  // Interstitial 광고를 화면에 표시합니다.
  [interstitial presentOnViewController:self];
}

- (void)BuzzInterstitialDidFailToLoadAd:(BuzzInterstitial *)interstitial withError:(NSError *)error {
  // 할당된 광고가 없으면 호출됩니다.
}

- (void)BuzzInterstitialDidDismiss:(UIViewController *)viewController {
  // Interstitial 지면이 종료되면 호출됩니다.
  // 필요에 따라 추가 기능을 구현하세요.
}

@end
```

참고 - 변경 전 코드(BuzzAdBenefit SDK v5)

**Swift**

```swift
import UIKit
import BuzzvilSDK

final class ViewController: UIViewController, BZVBuzzAdInterstitialDelegate {
  let buzzAdInterstitial = BZVBuzzAdInterstitial { builder in
    builder.unitId = "YOUR_INTERSTITIAL_UNIT_ID"
    builder.type = .dialog
  }

  override func viewDidLoad() {
    super.viewDidLoad()

    buzzAdInterstitial.delegate = self
    buzzAdInterstitial.load()
  }
}
extension ViewController: BZVBuzzAdInterstitialDelegate {
  func bzvBuzzAdInterstitialDidLoadAd(_ interstitial: BZVBuzzAdInterstitial) {
    // 할당된 광고가 있으면 호출됩니다.
    // Interstitial 광고를 화면에 표시합니다.
    interstitial.present(on: self)
  }
  
  func bzvBuzzAdInterstitialDidFail(toLoadAd interstitial: BZVBuzzAdInterstitial, withError error: Error) {
    // 할당된 광고가 없으면 호출됩니다.
  }
  
  func bzvBuzzAdInterstitialDidDismiss(_ viewController: UIViewController) {
    // Interstitial 지면이 종료되면 호출됩니다.
    // 필요에 따라 추가 기능을 구현하세요.
  }
}
```

**Objective-C**

```objectivec
@import BuzzvilSDK;

@interface ViewController () <BZVBuzzAdInterstitialDelegate>

@property (nonatomic, strong, readonly) BZVBuzzAdInterstitial *buzzAdInterstitial;

@end

@implementation ViewController

- (void)viewDidLoad {
  [super viewDidLoad];

  _buzzAdInterstitial = [BZVBuzzAdInterstitial interstitialWithBlock:^(BZVBuzzAdInterstitialBuilder * _Nonnull builder) {
    builder.unitId = @"YOUR_INTERSTITIAL_UNIT_ID";
    builder.type = BZVBuzzAdInterstitialTypeDialog;
  }];
  _buzzAdInterstitial.delegate = self;
  [_buzzAdInterstitial load];
}

#pragma mark - BZVBuzzAdInterstitialDelegate
- (void)BZVBuzzAdInterstitialDidLoadAd:(BZVBuzzAdInterstitial *)interstitial {
  // 할당된 광고가 있으면 호출됩니다.
  // Interstitial 광고를 화면에 표시합니다.
  [interstitial presentOnViewController:self];
}

- (void)BZVBuzzAdInterstitialDidFailToLoadAd:(BZVBuzzAdInterstitial *)interstitial withError:(NSError *)error {
  // 할당된 광고가 없으면 호출됩니다.
}

- (void)BZVBuzzAdInterstitialDidDismiss:(UIViewController *)viewController {
  // Interstitial 지면이 종료되면 호출됩니다.
  // 필요에 따라 추가 기능을 구현하세요.
}

@end
```

### 3 단계. 인터스티셜에 베네핏허브 진입점 추가하기

Intersitial 에서 베네핏허브로 갈 수 있는 버튼을 추가하는 옵션이 변경 되었습니다. 더이상 옵션이 제공되는 형태가 아닌 진입점이 항상 보이는 형태로 업데이트 되었습니다. 기존의 `buzzAdBenefitRouter` 관련 코드가 삭제 되어야 합니다.

**Swift**

```swift
let feedConfig = BZVFeedConfig { builder in
  builder.unitID = "YOUR_FEED_UNIT_ID"
}

let buzzAdInterstitial = BZVBuzzAdInterstitial { builder in
  builder.unitId = "YOUR_INTERSTITIAL_UNIT_ID"
  builder.type = .dialog
  builder.buzzAdBenefitRouter = BuzzBenefitRouterFactory.createFeedRouter(feedConfig) // 삭제 처리
}
```

**Objective-C**

```objectivec
BZVFeedConfig *feedConfig = [BZVFeedConfig configWithBlock:^(BZVFeedConfigBuilder * _Nonnull builder) {
  builder.unitID = @"YOUR_FEED_UNIT_ID";
}];

BZVBuzzAdInterstitial *buzzAdInterstitial = [BZVBuzzAdInterstitial interstitialWithBlock:^(BZVBuzzAdInterstitialBuilder * _Nonnull builder) {
  builder.unitId = @"YOUR_INTERSTITIAL_UNIT_ID";
  builder.type = BZVBuzzAdInterstitialTypeDialog;
  builder.buzzAdBenefitRouter = [BuzzBenefitRouterFactory createFeedRouter:feedConfig];
}];
```

## 버즈배너 (BuzzBanner)

기존에 제공하던 클래스들의 이름이 변경 되었습니다. 아래를 확인하여 적절하게 변환해야 합니다.

| AS-IS                           | TO-BE                  |
| ------------------------------- | ---------------------- |
| BuzzAdBenefitBannerView         | BuzzBannerSize         |
| BuzzAdBenefitBannerSize         | BuzzBannerView         |
| BuzzAdBenefitBannerViewDelegate | BuzzBannerViewDelegate |

**Swift**

```swift
import UIKit
import BuzzvilSDK

final class ViewController: UIViewController {
  private lazy var bannerView: BuzzBannerView = {
    let bannerView = BuzzBannerView(frame: .zero)
    bannerView.delegate = self
    return bannerView
  }()

  override func viewDidLoad() {
    super.viewDidLoad()

    let config = BuzzBannerConfig.Builder(placementId: placementID)
      .setSize(.w320h50)
      .build()
    bannerView.setConfig(rootViewController: self, config: config)

    view.addSubview(bannerView)

    // ...
  }

  override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)

    bannerView.requestAd()
  }

  override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)

    bannerView.removeAd()
  }
}

extension ViewController: BuzzBannerViewDelegate {
  func bannerView(_ bannerView: BuzzBannerView, didLoadApid: String) {
    // Banner에 광고가 할당 되었을 때 호출 됩니다.
  }
  
  func bannerView(_ bannerView: BuzzBannerView, didFailApid: String, error: NSError) {
    // Banner에 광고 할당이 실패했을 때 호출 됩니다.
  }
  
  func bannerView(_ bannerView: BuzzBannerView, didClickApid: String) {
    // Banner가 클릭되었을 때 호출 됩니다.
  }
  
  func bannerView(_ bannerView: BuzzBannerView, didRemoveApid: String) {
    // Banner가 제거되었을 떄 호출 됩니다.
  }
}
```

**Objective-C**

```objectivec
@import BuzzvilSDK;

@interface ViewController () <BuzzBannerViewDelegate>

@property (nonatomic, strong, readonly) BuzzBannerView *bannerView;

@end

@implementation ViewController

- (void)viewDidLoad {
  [super viewDidLoad];
  
  [self setupView];
}

- (void)setupView {
  BuzzBannerConfig * config = [BuzzBannerConfig configWith:^(BuzzBannerConfigBuilder * _Nonnull builder) {
    builder.placementId = @"YOUR_PLCEMENT_ID";
    builder.size = BuzzBannerSizeW320h50;
  }];
  _bannerView = [[BuzzBannerView alloc] initWithFrame:CGRectZero];
  [_bannerView setConfigWithRootViewController:self config:config];
  
  [self.view addSubview:_bannerView];
}

- (void)viewWillAppear:(BOOL)animated {
  [super viewWillAppear:animated];
  
  [_bannerView requestAd];
}

- (void)viewWillDisappear:(BOOL)animated{
  [super viewWillDisappear:animated];
  
  [_bannerView removeAd];
}

#pragma mark - BuzzBannerViewDelegate

- (void)bannerView:(BuzzBannerView * _Nonnull)bannerView didClickApid:(NSString * _Nonnull)didClickApid { 
  // Banner에 광고가 할당 되었을 때 호출 됩니다.
}

- (void)bannerView:(BuzzBannerView * _Nonnull)bannerView didFailApid:(NSString * _Nonnull)didFailApid error:(NSError * _Nonnull)error { 
  // Banner에 광고 할당이 실패했을 때 호출 됩니다.
}

- (void)bannerView:(BuzzBannerView * _Nonnull)bannerView didLoadApid:(NSString * _Nonnull)didLoadApid { 
  // Banner가 클릭되었을 때 호출 됩니다.
}

- (void)bannerView:(BuzzBannerView * _Nonnull)bannerView didRemoveApid:(NSString * _Nonnull)didRemoveApid { 
  // Banner가 제거되었을 떄 호출 됩니다.
}

@end
```

참고 - 변경 전 코드(BuzzAdBenefit SDK v5)

**Swift**

```swift
import UIKit
import BuzzvilSDK

final class ViewController: UIViewController {
  private lazy var bannerView: BuzzAdBenefitBannerView = {
    let bannerView = BuzzAdBenefitBannerView(frame: .zero)
    bannerView.delegate = self
    return bannerView
  }()

  override func viewDidLoad() {
    super.viewDidLoad()

    let config = BuzzAdBenefitBannerConfig.Builder(placementID: placementID)
      .setSize(.w320h50)
      .build()
    bannerView.setConfig(rootViewController: self, config: config)

    view.addSubview(bannerView)

    // ...
  }

  override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)

    bannerView.requestAd()
  }

  override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)

    bannerView.removeAd()
  }
}

extension ViewController: BuzzAdBenefitBannerViewDelegate {
  func bannerView(_ bannerView: BuzzAdBenefitBannerView, didLoadApid: String) {
    // Banner에 광고가 할당 되었을 때 호출 됩니다.
  }
  
  func bannerView(_ bannerView: BuzzAdBenefitBannerView, didFailApid: String, error: NSError) {
    // Banner에 광고 할당이 실패했을 때 호출 됩니다.
  }
  
  func bannerView(_ bannerView: BuzzAdBenefitBannerView, didClickApid: String) {
    // Banner가 클릭되었을 때 호출 됩니다.
  }
  
  func bannerView(_ bannerView: BuzzAdBenefitSDK.BuzzAdBenefitBannerView, didRemoveApid: String) {
    // Banner가 제거되었을 떄 호출 됩니다.
  }
}
```

**Objective-C**

```objectivec
@import BuzzvilSDK;

@interface ViewController () <BuzzAdBenefitBannerViewDelegate>

@property (nonatomic, strong, readonly) BuzzAdBenefitBannerView *bannerView;

@end

@implementation ViewController

- (void)viewDidLoad {
  [super viewDidLoad];
  
  [self setupView];
}

- (void)setupView {
  BuzzAdBenefitBannerConfig * config = [BuzzAdBenefitBannerConfig configWithBlock:^(BuzzAdBenefitBannerConfigBuilder * _Nonnull builder) {
    builder.placementID = @"YOUR_PLACEMENT_ID";
    builder.size = BuzzAdBenefitBannerSizeW320h50;
  }];
  _bannerView = [[BuzzAdBenefitBannerView alloc] initWithFrame:CGRectZero];
  [_bannerView setConfigWithRootViewController:self config:config];
  
  [self.view addSubview:_bannerView];
}

- (void)viewWillAppear:(BOOL)animated {
  [super viewWillAppear:animated];
  
  [_bannerView requestAd];
}

- (void)viewWillDisappear:(BOOL)animated{
  [super viewWillDisappear:animated];
  
  [_bannerView removeAd];
}

#pragma mark - BuzzAdBenefitBannerViewDelegate

- (void)bannerView:(BuzzAdBenefitBannerView * _Nonnull)bannerView didClickApid:(NSString * _Nonnull)didClickApid { 
  // Banner에 광고가 할당 되었을 때 호출 됩니다.
}

- (void)bannerView:(BuzzAdBenefitBannerView * _Nonnull)bannerView didFailApid:(NSString * _Nonnull)didFailApid error:(NSError * _Nonnull)error { 
  // Banner에 광고 할당이 실패했을 때 호출 됩니다.
}

- (void)bannerView:(BuzzAdBenefitBannerView * _Nonnull)bannerView didLoadApid:(NSString * _Nonnull)didLoadApid { 
  // Banner가 클릭되었을 때 호출 됩니다.
}

- (void)bannerView:(BuzzAdBenefitBannerView * _Nonnull)bannerView didRemoveApid:(NSString * _Nonnull)didRemoveApid { 
  // Banner가 제거되었을 떄 호출 됩니다.
}

@end
```

## UI 설정

기존에 제공하뎐 Theme 관련 코드는 대부분 사라지고 CTA 버튼 자체 구현만 남아있습니다. 다른 색상관련 코드는 삭제처리가 필요합니다. 주요 색상을 설정하기 위해서는 버즈빌 담당자(<help@buzzvil.com>)을 통해 서버설정으로 설정할 수 있습니다.

### CTA 버튼 자체 구현

CTA 버튼 자체 구현 시 필요 한 프로토콜 이름이 변경 되었습니다. `BZVCtaViewProtocol` -> `BuzzCtaViewProtocol`

**Swift**

```swift
// MARK: BZVCtaViewProtocol
protocol BZVCtaViewProtocol {
  // 리워드가 없는 광고에 대한 CTA 뷰 레이아웃을 정의합니다.
  func renderRewardNotAvailableViewState(withCtaText ctaText: String)

  // 리워드가 있는 광고에 대한 CTA 뷰 레이아웃을 정의합니다.
  func renderRewardAvailableViewState(withCtaText ctaText: String, reward: Int)

  // 참여 확인 중인 광고에 대한 CTA 뷰 레이아웃을 정의합니다.
  func renderParticipatingViewState(withCtaText ctaText: String)

  // 참여 완료한 광고에 대한 CTA 뷰 레이아웃을 정의합니다.
  func renderParticipatedViewState(withCtaText ctaText: String)
}
```

**Objective-C**

```objectivec
@objc
public protocol BuzzCtaViewProtocol: AnyObject {
  @objc
  func renderParticipatingViewState(ctaText: String)
  
  @objc
  func renderParticipatedViewState(ctaText: String)
  
  @objc
  func renderRewardAvailableViewState(ctaText: String, reward: Int)
  
  @objc
  func renderRewardNotAvailableViewState(ctaText: String)
}
```

## 자체 구현 인앱 브라우저

해당 버전에서는 자체 구현 인앱 브라우저를 지원하지 않습니다. 이전에 제공하던 `BuzzAdBrowser`, `BZVLauncher`, `BZVLauncherDelegate` 관련 코드가 삭제되어야 합니다

참고 - 변경 전 코드(BuzzAdBenefit SDK v5)

**Swift**

```swift
import UIKit
import BuzzvilSDK

final class CustomBrowserViewController: UIViewController {
  private lazy var browserViewController: UIViewController = {
    BuzzAdBrowser.sharedInstance().browserViewController()
  }()
  
  override func viewDidLoad() {
    super.viewDidLoad()
    
    displayContentViewController(browserViewController)
  }

  private func displayContentViewController(_ contentViewController: UIViewController) {
    addChild(contentViewController)
    contentViewController.view.frame = view.bounds
    view.addSubview(contentViewController.view)
    contentViewController.didMove(toParent: self)
  }
}
```

**Objective-C**

```objectivec
@interface CustomBrowserViewController: UIViewController

@end

@interface CustomBrowserViewController ()

@property (nonatomic, strong, readonly) UIViewController *browserViewController;

@end

@implementation CustomBrowserViewController

- (void)viewDidLoad {
  [super viewDidLoad];

  _browserViewController = [BuzzAdBrowser.sharedInstance browserViewController];
  [self displayContentViewController:_browserViewController];
}

- (void)displayContentViewController:(UIViewController *)contentViewController {
  [self addChildViewController:contentViewController];
  contentViewController.view.frame = self.view.bounds;
  [self.view addSubview:contentViewController.view];
  [contentViewController didMoveToParentViewController:self];
}

@end
```

**Swift**

```swift
import Foundation
import BuzzvilSDK

final class CustomLauncher: NSObject, BZVLauncher {
  // 런처와 관련된 이벤트를 수신할 수 있습니다.
  var delegate: BZVLauncherDelegate?

  func open(with launchInfo: BZVLaunchInfo) {
    // launchInfo의 인자를 확인하여 광고 또는 콘텐츠인지 미리 판단할 수 있습니다.
    if let ad = launchInfo.ad {
      if ad.isDeepLink {
        // 딥링크 광고일 경우 필요한 작업을 할 수 있습니다.
      }
    } else if let article = launchInfo.article {
      let sourceURL = article.sourceURL
    }

    let customBrowserViewController = CustomBrowserViewController()
    YOUR_ROOT_VIEW_CONTROLLER.presentedViewController?.present(customBrowserViewController, animated: true, completion: nil)
  }
}
```

**Objective-C**

```objectivec
@import BuzzvilSDK;

@interface CustomLauncher : NSObject <BZVLauncher>

// 런처와 관련된 이벤트를 수신할 수 있습니다.
@property (nonatomic, weak, readwrite, nullable) id<BZVLauncherDelegate> delegate;

@end

@implementation CustomLauncher

- (void)openWithLaunchInfo:(BZVLaunchInfo *)launchInfo {
  // launchInfo의 인자를 확인하여 광고 또는 콘텐츠인지 미리 판단할 수 있습니다.
  if (launchInfo.ad != nil) {
    if (launchInfo.ad.isDeepLink) {
      // 딥링크 광고일 경우 필요한 작업을 할 수 있습니다.
    }
  } else if (launchInfo.article != nil){
    NSString *sourceURL = launchInfo.article.sourceURL;
  }

  // Custom Browser 실행
  CustomBrowserViewController *customBrowserViewController = [[CustomBrowserViewController alloc] init];
  [YOUR_ROOT_VIEW_CONTROLLER.presentedViewController presentViewController:customBrowserViewController animated:YES completion:nil];
}

@end
```

**Swift**

```swift
let launcher = CustomLauncher()
BuzzAdBenefit.setLauncher(launcher)
```

**Objective-C**

```objectivec
CustomLauncher *launcher = [[CustomLauncher alloc] init];
[BuzzAdBenefit setLauncher:launcher];
```

## 개인정보 처리방침 동의하기

개인정보 처리방침에 대한 동의 여부와 동의를 하기 위한 함수가 변경 되었습니다.

| 상태값 | enum                               |
| --- | ---------------------------------- |
| 동의  | `BuzzPrivacyConsentStatus.granted` |
| 거부  | `BuzzPrivacyConsentStatus.revoked` |

**Swift**

```swift
BuzzAdBenefit.shared.loadPrivacyConsentStatus(onSuccess: { [weak self] status in
  // 현재 개인정보 처리 방침 상태를 가져올 수 있습니다
}, onFailure: { [weak self] error in
  // 개인정보 처리방침에 대한 상태를 가져오는데 실패 했을 경우 호출 됩니다.
})

BuzzAdBenefit.shared.grantPrivacyConsent(onSuccess: { [weak self] in
  // 개인정보 처리방침 동의에 성공했을 경우 호출 됩니다.
}, onFailure: { [weak self] error in
  // 개인정보 처리방침 동의 요청에 실패했을 경우 호출 됩니다.
})
```

**Objective-C**

```objectivec
[BuzzAdBenefit.sharedInstance loadPrivacyConsentStatusOnSuccess:^(enum BuzzPrivacyConsentStatus status) {
  // 현재 개인정보 처리 방침 상태를 가져올 수 있습니다
} onFailure:^(NSError * _Nonnull error) {
  // 개인정보 처리방침에 대한 상태를 가져오는데 실패 했을 경우 호출 됩니다.
}];

[BuzzAdBenefit.sharedInstance grantPrivacyConsentOnSuccess:^{
  // 개인정보 처리방침 동의에 성공했을 경우 호출 됩니다.
} onFailure:^(NSError * _Nonnull error) {
  // 개인정보 처리방침 동의 요청에 실패했을 경우 호출 됩니다.
}];

```

참고 - 변경 전 코드(BuzzAdBenefit SDK v5)

**Swift**

```swift
let privacyPolicyManager = BuzzAdBenefit.privacyPolicyManager

// 직접 구현한 개인정보 제3자 제공 동의 UI에서 동의를 받았을 경우 아래 코드를 실행하면, 피드 화면에서 개인정보 제3자 제공 동의 UI가 노출되지 않으면서 광고 할당이 정상적으로 진행 됩니다.
// 아래의 코드를 실행하지 않을 경우 피드 진입 시 개인정보 제3자 제공 동의 UI가 노출되기 때문에 필수적으로 실행이 필요합니다.
privacyPolicyManager.grantConsent()

// 아래 코드를 통해서 수집 동의를 철회할 수 있습니다. 이 코드가 실행되면 피드에서 광고 할당이 이루어지지 않습니다.
privacyPolicyManager.revokeConsent()
```

**Objective-C**

```objectivec
BZVPrivacyPolicyManager *privacyPolicyManager = [BuzzAdBenefit privacyPolicyManager];

// 직접 구현한 개인정보 제3자 제공 동의 UI 에서 동의를 받았을 경우 아래 코드를 실행하면, 피드 화면에서 개인정보 제3자 제공 동의 UI가 노출되지 않으면서 광고 할당이 정상적으로 진행 됩니다.
// 아래의 코드를 실행하지 않을 경우 피드 진입 시 개인정보 제3자 제공 동의 UI가 노출되기 때문에 필수적으로 실행이 필요합니다.
[privacyPolicyManager grantConsent];

// 아래 코드를 통해서 수집 동의를 철회할 수 있습니다. 이 코드가 실행되면 피드에서 광고 할당이 이루어지지 않습니다.
[privacyPolicyManager revokeConsent];
```

## 미션팩

기존에 단독으로 제공하던 `BuzzAdMissionPack` 클래스가 삭제되고 `BuzzBenefitHub` 로 통합 되었습니다. 관련 코드 삭제가 필요합니다.

참고 - 변경 전 코드(BuzzAdBenefit SDK v5)

**Swift**

```swift
import UIKit
import BuzzvilSDK

class MissionPackViewController: UIViewController {
  let missionPack = BuzzAdBenefitMissionPack(unitId: "YOUR_MISSION_PACK_UNIT_ID")
  
  override func viewDidLoad() {
    super.viewDidLoad()
    
    showMissionPack()
  }
  
  // missionPack 사용가능한지 체크하기
  func checkCanOpenMissionPack() {
    missionPack.canOpen {
      print ("MissionPack Can open !")
    } onFailure: { error in
      print ("MissionPack Can't open error: \(error.localizedDescription)")
    }
  }
  
  // missionPack 화면에 표시하기
  func showMissionPack() {
    missionPack.show(on: self, onFailure: { error in
      print ("MissionPack Can't open error: \(error.localizedDescription)")
    })
  }
}
```

**Objective-C**

```objectivec
@import BuzzvilSDK;
#import "MissionPackViewController.h"

@interface MissionPackViewController()

@property (nonatomic, strong, readonly) BuzzAdBenefitMissionPack * missionPack;

@end

@implementation MissionPackViewController

- (void)viewDidLoad {
  [super viewDidLoad];
  
  _missionPack = [[BuzzAdBenefitMissionPack alloc] initWithUnitId:@"YOUR_MISSION_PACK_UNIT_ID"];
}

- (void)checkCanOpenMissionPack {
  [_missionPack canOpenOnSuccess:^{
    // missionPack 이 열릴 수 있을 때 호출 됩니다.
  } onFailure:^(NSError * _Nonnull error) {
    // missionPack 이 열릴 수 없을 때 호출 됩니다.
  }];
}

- (void)showMissionPack {
  [_missionPack showOn:self onFailure:^(NSError * _Nonnull error) {
    // missionPack 이 열릴 수 없을 때 호출 됩니다.
  }];
}

@end

```
