简体   繁体   中英

How can I access an SwiftUI environment object from an NSObject?

I'm trying to increment the variable adsWatched by 1 when an ad is dismissed by changing the environment object from a UIViewController and passing it to a SwiftUI view. I've tried putting an environment object in my NSObject class AdManager, which contains the function I want to change the environment object in, but I get the error message "Unknown attribute 'EnvironmentObject'":

    public protocol AdManagerRewardDelegate{
func rewardAdGiveRewardToUser(type:String, amount: NSDecimalNumber)
func rewardAdFailedToLoad()
func rewardAdDidReceive(
    rewardViewController: UIViewController?,
    rewardedAd: GADRewardedAd?,
    delegate: AdManager
)
func rewardAdDidOpen()
func rewardAdDidClose()
func rewardAdFailedToPresent()
}


//default implementation AdManagerRewardDelegate
public extension AdManagerRewardDelegate{
func rewardAdGiveRewardToUser(type:String, amount: NSDecimalNumber) {}
func rewardAdFailedToLoad() {}
func rewardAdDidReceive(
    rewardViewController: UIViewController?,
    rewardedAd: GADRewardedAd?,
    delegate: AdManager
) {
    if rewardedAd?.isReady == true {
        if let rewardViewController = rewardViewController {
            rewardedAd?.present(fromRootViewController: rewardViewController, delegate: delegate)
        }
    }
}
func rewardAdDidOpen() {}
func rewardAdDidClose() {}
func rewardAdFailedToPresent() {}
}

public class AdManager: NSObject {
public static let shared = AdManager()
public var ADS_DISABLED = false

public var delegateReward: AdManagerRewardDelegate?

private var viewController:UIViewController?
private var bannerViewContainer:UIView?
private var rewardViewController:UIViewController?

var interestial:GADInterstitial?
private var testDevices:[String] = [""]


private var rewardedAd: GADRewardedAd?

let borderSizeBetweenBannerAndContent:CGFloat = 5

@EnvironmentObject var settings: UserSettings


public override init() {
    super.init()
}

public func configureWithApp(){
    GADMobileAds.sharedInstance().requestConfiguration.testDeviceIdentifiers = testDevices
}

public func setTestDevics(testDevices: [String]){
    self.testDevices = testDevices
    self.testDevices += [kGADSimulatorID as! String ] //all simulator
}

private func getGADRequest() -> GADRequest{
    let request = GADRequest()
    return request
}



// MARK:- Reward Video Ads
public func loadAndShowRewardAd(_ adUnit: String, viewController: UIViewController){
    self.rewardViewController = viewController
    
    rewardedAd = GADRewardedAd(adUnitID: adUnit)
    rewardedAd?.load(getGADRequest()) { error in
      if let error = error {
        // Handle ad failed to load case.
        print("Reward based video ad failed to load. \(error.debugDescription)")
        self.delegateReward?.rewardAdFailedToLoad()
      } else {
        // Ad successfully loaded.
        print("Reward based video ad is received.")
        self.delegateReward?.rewardAdDidReceive(
            rewardViewController: self.rewardViewController,
            rewardedAd: self.rewardedAd,
            delegate: self
        )
      }
    }
}
}


// MARK:- GADRewardBasedVideoAdDelegate
extension AdManager : GADRewardedAdDelegate {
public func rewardedAdDidPresent(_ rewardedAd: GADRewardedAd) {
    print("Rewarded ad presented.")
    delegateReward?.rewardAdDidOpen()
}

public func rewardedAd(_ rewardedAd: GADRewardedAd, didFailToPresentWithError error: Error) {
    print("Rewarded ad failed to present.")
    delegateReward?.rewardAdFailedToPresent()
}

public func rewardedAdDidDismiss(_ rewardedAd: GADRewardedAd) {
    print("Rewarded ad dismissed.")
    // i want to increase adsWatched by 1 here
    settings.adsWatched += 1
    delegateReward?.rewardAdDidClose()
}

public func rewardedAd(_ rewardedAd: GADRewardedAd, userDidEarn reward: GADAdReward) {
    print("Reward received with currency: \(reward.type), amount \(reward.amount).")
    delegateReward?.rewardAdGiveRewardToUser(type: reward.type, amount: reward.amount)
}
}

I've tried passing the object to it from my view controller, but I get the error message: "Instance member 'environmentObject' of type 'View' cannot be used on instance of nested type 'Ads.ViewController'" for this:

    struct Ads: UIViewControllerRepresentable {
    
    @EnvironmentObject var settings: UserSettings
    
    @Environment(\.presentationMode) var presentationMode: Binding<PresentationMode>
    

typealias UIViewControllerType = UIViewController
    

func makeUIViewController(context: Context) -> UIViewController {
    return ViewController()
}

func updateUIViewController(_ uiView: UIViewController, context: Context) {
}

class ViewController: UIViewController, GADRewardedAdDelegate, AdManagerRewardDelegate {
    
var rewardedAd: GADRewardedAd?
    
@Environment(\.presentationMode) var presentationMode: Binding<PresentationMode>
    
    @EnvironmentObject var settings: UserSettings
    
override func viewDidLoad() {
super.viewDidLoad()
        
    AdManager.shared.loadAndShowRewardAd(AdIds.rewarded.rawValue, viewController: self, environmentObject(settings))
    // error messages here^: "Extra argument in call","Instance member 'environmentObject' of type 'View' cannot be used on instance of nested type 'Ads.ViewController'"
    AdManager.shared.delegateReward = self
    }
    

    func rewardedAd(_ rewardedAd: GADRewardedAd, userDidEarn reward: GADAdReward) {
      print("Reward received: \(reward.type), amount \(reward.amount).")
    }
    
}
}

Is there any way I can change the variable from an NSObject?

The settings here is just a reference so you can pass it via arguments

public func loadAndShowRewardAd(_ adUnit: String, viewController: UIViewController,
                                settings: UserSettings) {
    self.rewardViewController = viewController
    // ... other code
}

and in your representable

struct Ads: UIViewControllerRepresentable {

    @EnvironmentObject var settings: UserSettings
    @Environment(\.presentationMode) var presentationMode: Binding<PresentationMode>


    typealias UIViewControllerType = UIViewController


    func makeUIViewController(context: Context) -> UIViewController {
        return ViewController(settings: settings, mode: presentationMode)
    }

    func updateUIViewController(_ uiView: UIViewController, context: Context) {
    }

    class ViewController: UIViewController, GADRewardedAdDelegate, AdManagerRewardDelegate {

        var rewardedAd: GADRewardedAd?
        var presentationMode: Binding<PresentationMode>
        var settings: UserSettings

        init(settings: UserSettings, mode: Binding<PresentationMode>) {
            self.settings = settings
            self.presentationMode = mode
        }

        override func viewDidLoad() {
            super.viewDidLoad()

            AdManager.shared.loadAndShowRewardAd(AdIds.rewarded.rawValue, viewController: self, settings: settings)
            // error messages here^: "Extra argument in call","Instance member 'environmentObject' of type 'View' cannot be used on instance of nested type 'Ads.ViewController'"
            AdManager.shared.delegateReward = self
        }


        func rewardedAd(_ rewardedAd: GADRewardedAd, userDidEarn reward: GADAdReward) {
            print("Reward received: \(reward.type), amount \(reward.amount).")
        }

    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM