Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/swift/16.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Swift @State更改后,SwfitUI元素不会更改_Swift_Swiftui - Fatal编程技术网

Swift @State更改后,SwfitUI元素不会更改

Swift @State更改后,SwfitUI元素不会更改,swift,swiftui,Swift,Swiftui,说到SwiftUI,我是个新手。我试图构建的是入职屏幕。我目前正在使用的其中一个屏幕是,当我需要向用户请求一系列隐私信息时,比如访问相机、苹果照片库、麦克风、位置和通知。 和 现在,我开始运行应用程序并单击蓝色的“允许”按钮开始请求用户的数据。 当涉及到请求位置和通知数据时,问题开始出现。首先,我做了一个选择,UI元素[checkmark]没有显示出来,这是我试图解决的第一个问题。但是当我再次点击蓝色的Allow按钮时,它同时显示了两个复选标记(用于位置和通知),这是第二个问题。类似于通知复

说到SwiftUI,我是个新手。我试图构建的是入职屏幕。我目前正在使用的其中一个屏幕是,当我需要向用户请求一系列隐私信息时,比如访问相机、苹果照片库、麦克风、位置和通知。 和

现在,我开始运行应用程序并单击蓝色的“允许”按钮开始请求用户的数据。

当涉及到请求位置和通知数据时,问题开始出现。首先,我做了一个选择,UI元素[checkmark]没有显示出来,这是我试图解决的第一个问题。但是当我再次点击蓝色的Allow按钮时,它同时显示了两个复选标记(用于位置和通知),这是第二个问题。类似于通知复选标记的相同问题,我需要再次单击蓝色的“允许”按钮

请帮我解决这些问题,因为我尽了全力。此外,以下是执行此操作的所有代码:

import SwiftUI
import AVFoundation
import Photos
import CoreLocation
import UserNotifications

struct ContentView: View {

@AppStorage("onBoardingViewed") var hasOnboarded = false
private var locationManager = CLLocationManager()

// MARK: - UI States

@State private var isAllowedCamera = false
@State private var isAllowedPhotoLibrary = false
@State private var isAllowedMicrophone = false
@State private var isAllowedLocation = false
@State private var isAllowedNotification = false

@State private var isHiddenCam = true
@State private var isHiddenPL = true
@State private var isHiddenMic = true
@State private var isHiddenLoc = true
@State private var isHiddenNot = true

@State private var isFinished = false

// MARK: - UI

var body: some View {
    VStack(spacing: 60) {
        
        Text("Allow Access")
            .font(.system(.largeTitle, design: .rounded))
            .fontWeight(.bold)
            
        HStack(spacing: 20) {
            VStack(alignment: .center, spacing: 20) {
                Image(systemName: isAllowedCamera ? "checkmark.circle" : "xmark.circle")
                    .foregroundColor(isAllowedCamera ? Color.green : Color.red)
                    .font(.largeTitle)
                    .scaleEffect(isHiddenCam ? 0 : 1)
                    .animation(.spring())
                
                Image(systemName: isAllowedPhotoLibrary ? "checkmark.circle" : "xmark.circle")
                    .foregroundColor(isAllowedPhotoLibrary ? Color.green : Color.red)
                    .font(.largeTitle)
                    .scaleEffect(isHiddenPL ? 0 : 1)
                    .animation(.spring())
                
                Image(systemName: isAllowedMicrophone ? "checkmark.circle" : "xmark.circle")
                    .foregroundColor(isAllowedMicrophone ? Color.green : Color.red)
                    .font(.largeTitle)
                    .scaleEffect(isHiddenMic ? 0 : 1)
                    .animation(.spring())
                
                Image(systemName: isAllowedLocation ? "checkmark.circle" : "xmark.circle")
                    .foregroundColor(isAllowedLocation ? Color.green : Color.red)
                    .font(.largeTitle)
                    .scaleEffect(isHiddenLoc ? 0 : 1)
                    .animation(.spring())
                
                Image(systemName: isAllowedNotification ? "checkmark.circle" : "xmark.circle")
                    .foregroundColor(isAllowedNotification ? Color.green : Color.red)
                    .font(.largeTitle)
                    .scaleEffect(isHiddenLoc ? 0 : 1)
                    .animation(.spring())
            }
            
            VStack(alignment: .leading, spacing: 20) {
                Text("Camera permission")
                    .font(.title)
                    .fontWeight(.light)
                Text("Photos permission")
                    .font(.title)
                    .fontWeight(.light)
                Text("Microphone permission")
                    .font(.title)
                    .fontWeight(.light)
                Text("Location permission")
                    .font(.title)
                    .fontWeight(.light)
                Text("Notification permission")
                    .font(.title)
                    .fontWeight(.light)
            }
        }
        
        // MARK: - Action
        
        Button {
            
            reqestCamera { (success) in
                if success {
                    isAllowedCamera = true
                } else {
                    isAllowedCamera = false
                }
                isHiddenCam = false
            }
            
            reqestPhotoLibrary { (success) in
                if success {
                    isAllowedPhotoLibrary = true
                } else {
                    isAllowedPhotoLibrary = false
                }
                isHiddenPL = false
            }
            
            reqestMicrophone { (success) in
                if success {
                    isAllowedMicrophone = true
                } else {
                    isAllowedMicrophone = false
                }
                isHiddenMic = false
                
                reqestLocation { (success) in

                    if success == true {
                        isAllowedLocation = true
                        print("Location ON")
                    } else {
                        isAllowedLocation = false
                        print("Location OFF")
                    }

                    isHiddenLoc = false

                    reqestNotifications { (success) in
                        if success == true {
                            isAllowedNotification = true
                        } else {
                            isAllowedNotification = false
                        }

                        isHiddenNot = false
                        isFinished = true
                    }
                }
            }
            
            if isFinished == true {
                withAnimation {
                    hasOnboarded = true
                }
            }
            
        } label: {
            Text(isFinished ? "START" : "ALLOW")
                .font(.custom("SF-Compact-Rounded-Medium", size: 20))
                .foregroundColor(.white)
                .padding()
                .frame(width: 250, height: 50)
                .background(Color.blue)
                .cornerRadius(5)
        }
    }
}

// MARK: - Request access methods

private func reqestCamera(completion: @escaping (Bool) -> Void) {
    AVCaptureDevice.requestAccess(for: .video, completionHandler: completion)
}

private func reqestPhotoLibrary(completion: @escaping (Bool) -> Void) {
    PHPhotoLibrary.requestAuthorization(for: .addOnly) { (status) in
        switch status {
        case .authorized:
            completion(true)
        case .limited:
            completion(true)
        case .notDetermined:
            completion(false)
        case .restricted:
            completion(false)
        case .denied:
            completion(false)
        @unknown default:
            completion(false)
        }
    }
}

private func reqestMicrophone(completion: @escaping (Bool) -> Void) {
    AVCaptureDevice.requestAccess(for: .audio, completionHandler: completion)
}

private func reqestLocation(completion: @escaping (Bool) -> Void) {
    let status = locationManager.authorizationStatus
    DispatchQueue.main.async {
        locationManager.requestWhenInUseAuthorization()
        
        if status == .authorizedWhenInUse {
            print("autorized--------")
            completion(true)
        } else if status == .authorizedAlways {
            completion(true)
        } else if status == .denied {
            completion(false)
            print("denied--------")
        } else if status == .restricted {
            completion(false)
        }
    }
}

private func reqestNotifications(completion: @escaping (Bool) -> Void) {
    let center = UNUserNotificationCenter.current()
    
    DispatchQueue.main.async {
        center.requestAuthorization(options: [.alert, .badge, .sound]) { (success, error) in
            if success {
                completion(true)
            } else if let error = error {
                print(error.localizedDescription)
                completion(false)
            } else {
                completion(false)
            }
        }
    }
}
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}
更新代码

现在它有了入职屏幕和AllowAcsesView。我希望你现在能更清楚地看到这个问题。例如,当用户将在隐私请求进程的中间停止或将更新应用程序时,他将只查看位置许可的检查标记,并且在第一页将立即请求通知屏幕的许可,并且按钮不改变为“开始”标签


这里有一个可能的解决办法。我创建了两个新的管理器类,它们处理位置和通知请求

struct ContentView: View {

@AppStorage("onBoardingViewed") var hasOnboarded = false
private var locationManager = CLLocationManager()
    
@ObservedObject var locManager = LocationManager()
@ObservedObject var notificationManager = NotificationManager()

// MARK: - UI States

@State private var isAllowedCamera = false
@State private var isAllowedPhotoLibrary = false
@State private var isAllowedMicrophone = false
@State private var isAllowedLocation = false
@State private var isAllowedNotification = false

@State private var isHiddenCam = true
@State private var isHiddenPL = true
@State private var isHiddenMic = true
@State private var isHiddenLoc = true
@State private var isHiddenNot = true

@State private var isFinished = false

// MARK: - UI

var body: some View {
    VStack(spacing: 60) {
        
        Text("Allow Access")
            .font(.system(.largeTitle, design: .rounded))
            .fontWeight(.bold)
            
        HStack(spacing: 20) {
            VStack(alignment: .center, spacing: 20) {
                Image(systemName: isAllowedCamera ? "checkmark.circle" : "xmark.circle")
                    .foregroundColor(isAllowedCamera ? Color.green : Color.red)
                    .font(.largeTitle)
                    .scaleEffect(isHiddenCam ? 0 : 1)
                    .animation(.spring())
                
                Image(systemName: isAllowedPhotoLibrary ? "checkmark.circle" : "xmark.circle")
                    .foregroundColor(isAllowedPhotoLibrary ? Color.green : Color.red)
                    .font(.largeTitle)
                    .scaleEffect(isHiddenPL ? 0 : 1)
                    .animation(.spring())
                
                Image(systemName: isAllowedMicrophone ? "checkmark.circle" : "xmark.circle")
                    .foregroundColor(isAllowedMicrophone ? Color.green : Color.red)
                    .font(.largeTitle)
                    .scaleEffect(isHiddenMic ? 0 : 1)
                    .animation(.spring())
                
                Image(systemName: (locManager.authorisationStatus.rawValue == 4) ? "checkmark.circle" : "xmark.circle")
                    .foregroundColor((locManager.authorisationStatus.rawValue == 4) ? Color.green : Color.red)
                    .font(.largeTitle)
                    .scaleEffect(!locManager.showResult ? 0 : 1)
                    .animation(.spring())
                
                Image(systemName: notificationManager.allowedNotifications ? "checkmark.circle" : "xmark.circle")
                    .foregroundColor(notificationManager.allowedNotifications ? Color.green : Color.red)
                    .font(.largeTitle)
                    .scaleEffect(!notificationManager.showResult ? 0 : 1)
                    .animation(.spring())
            }
            
            VStack(alignment: .leading, spacing: 20) {
                Text("Camera permission")
                    .font(.title)
                    .fontWeight(.light)
                Text("Photos permission")
                    .font(.title)
                    .fontWeight(.light)
                Text("Microphone permission")
                    .font(.title)
                    .fontWeight(.light)
                Text("Location permission")
                    .font(.title)
                    .fontWeight(.light)
                Text("Notification permission")
                    .font(.title)
                    .fontWeight(.light)
            }
        }
        
        // MARK: - Action
        
        Button {
            
            reqestCamera { (success) in
                if success {
                    isAllowedCamera = true
                } else {
                    isAllowedCamera = false
                }
                isHiddenCam = false
            }
            
            reqestPhotoLibrary { (success) in
                if success {
                    isAllowedPhotoLibrary = true
                } else {
                    isAllowedPhotoLibrary = false
                }
                isHiddenPL = false
            }
            
            reqestMicrophone { (success) in
                if success {
                    isAllowedMicrophone = true
                } else {
                    isAllowedMicrophone = false
                }
                isHiddenMic = false
                

                self.locManager.notificationManager = notificationManager
                self.locManager.request()

            }
            
            if isFinished == true {
                withAnimation {
                    hasOnboarded = true
                }
            }
            
        } label: {
            Text(isFinished ? "START" : "ALLOW")
                .font(.custom("SF-Compact-Rounded-Medium", size: 20))
                .foregroundColor(.white)
                .padding()
                .frame(width: 250, height: 50)
                .background(Color.blue)
                .cornerRadius(5)
        }
    }
}
然后添加以下位置管理器类:

class LocationManager: NSObject, ObservableObject {
    private let locationManager = CLLocationManager()
    var authorisationStatus: CLAuthorizationStatus = .notDetermined {
        willSet {
            objectWillChange.send()
        }
    }
    
    var showResult = false {
        willSet {
            objectWillChange.send()
            notificationManager.requestPush()
        }
    }
    
    var notificationManager = NotificationManager()
    
    override init() {
        super.init()
        self.locationManager.delegate = self
    }

    public func request() {
        self.locationManager.requestWhenInUseAuthorization()
    }
}

extension LocationManager: CLLocationManagerDelegate {

    func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
        self.authorisationStatus = status
        
        if (status != .notDetermined) {
            self.showResult = true
        }
    }
    
}
以及以下通知管理器:

class NotificationManager : NSObject, ObservableObject {
    
    @Published var allowedNotifications = false
    @Published var showResult = false

    func requestPush() {
        let center = UNUserNotificationCenter.current()
        
        center.requestAuthorization(options: [.alert, .badge, .sound]) { (success, error) in
            if success {
                DispatchQueue.main.async {
                    self.allowedNotifications = true
                }
            } else if let error = error {
                print(error.localizedDescription)
            } else {
            }
            
            DispatchQueue.main.async {
                self.showResult = true
            }
        }
    }
}
我使用
观察对象
。位置和通知管理器充当
可观察对象
。当状态更新时,视图的图标也相应更新。问题是顺序,一个接一个地调用。这就是为什么必须将NotificationManager传递给LocationManager的原因。完成后,位置管理器将调用通知

顺便说一句,屏幕看起来很棒。这个图标真的很酷!ö

编辑:

下面是加载推送通知初始状态的更新

在NotificationManager内部添加以下
init()
方法

override init() {
    super.init()
    
    let center = UNUserNotificationCenter.current()
    center.getNotificationSettings { (settings) in
        if(settings.authorizationStatus == .authorized)
        {
            self.allowedNotifications = true
            self.showResult = true
        }
        else if (settings.authorizationStatus == .denied)
        {
            self.allowedNotifications = false
            self.showResult = true
        }
    }
}

这里有一个可能的解决办法。我创建了两个新的管理器类,它们处理位置和通知请求

struct ContentView: View {

@AppStorage("onBoardingViewed") var hasOnboarded = false
private var locationManager = CLLocationManager()
    
@ObservedObject var locManager = LocationManager()
@ObservedObject var notificationManager = NotificationManager()

// MARK: - UI States

@State private var isAllowedCamera = false
@State private var isAllowedPhotoLibrary = false
@State private var isAllowedMicrophone = false
@State private var isAllowedLocation = false
@State private var isAllowedNotification = false

@State private var isHiddenCam = true
@State private var isHiddenPL = true
@State private var isHiddenMic = true
@State private var isHiddenLoc = true
@State private var isHiddenNot = true

@State private var isFinished = false

// MARK: - UI

var body: some View {
    VStack(spacing: 60) {
        
        Text("Allow Access")
            .font(.system(.largeTitle, design: .rounded))
            .fontWeight(.bold)
            
        HStack(spacing: 20) {
            VStack(alignment: .center, spacing: 20) {
                Image(systemName: isAllowedCamera ? "checkmark.circle" : "xmark.circle")
                    .foregroundColor(isAllowedCamera ? Color.green : Color.red)
                    .font(.largeTitle)
                    .scaleEffect(isHiddenCam ? 0 : 1)
                    .animation(.spring())
                
                Image(systemName: isAllowedPhotoLibrary ? "checkmark.circle" : "xmark.circle")
                    .foregroundColor(isAllowedPhotoLibrary ? Color.green : Color.red)
                    .font(.largeTitle)
                    .scaleEffect(isHiddenPL ? 0 : 1)
                    .animation(.spring())
                
                Image(systemName: isAllowedMicrophone ? "checkmark.circle" : "xmark.circle")
                    .foregroundColor(isAllowedMicrophone ? Color.green : Color.red)
                    .font(.largeTitle)
                    .scaleEffect(isHiddenMic ? 0 : 1)
                    .animation(.spring())
                
                Image(systemName: (locManager.authorisationStatus.rawValue == 4) ? "checkmark.circle" : "xmark.circle")
                    .foregroundColor((locManager.authorisationStatus.rawValue == 4) ? Color.green : Color.red)
                    .font(.largeTitle)
                    .scaleEffect(!locManager.showResult ? 0 : 1)
                    .animation(.spring())
                
                Image(systemName: notificationManager.allowedNotifications ? "checkmark.circle" : "xmark.circle")
                    .foregroundColor(notificationManager.allowedNotifications ? Color.green : Color.red)
                    .font(.largeTitle)
                    .scaleEffect(!notificationManager.showResult ? 0 : 1)
                    .animation(.spring())
            }
            
            VStack(alignment: .leading, spacing: 20) {
                Text("Camera permission")
                    .font(.title)
                    .fontWeight(.light)
                Text("Photos permission")
                    .font(.title)
                    .fontWeight(.light)
                Text("Microphone permission")
                    .font(.title)
                    .fontWeight(.light)
                Text("Location permission")
                    .font(.title)
                    .fontWeight(.light)
                Text("Notification permission")
                    .font(.title)
                    .fontWeight(.light)
            }
        }
        
        // MARK: - Action
        
        Button {
            
            reqestCamera { (success) in
                if success {
                    isAllowedCamera = true
                } else {
                    isAllowedCamera = false
                }
                isHiddenCam = false
            }
            
            reqestPhotoLibrary { (success) in
                if success {
                    isAllowedPhotoLibrary = true
                } else {
                    isAllowedPhotoLibrary = false
                }
                isHiddenPL = false
            }
            
            reqestMicrophone { (success) in
                if success {
                    isAllowedMicrophone = true
                } else {
                    isAllowedMicrophone = false
                }
                isHiddenMic = false
                

                self.locManager.notificationManager = notificationManager
                self.locManager.request()

            }
            
            if isFinished == true {
                withAnimation {
                    hasOnboarded = true
                }
            }
            
        } label: {
            Text(isFinished ? "START" : "ALLOW")
                .font(.custom("SF-Compact-Rounded-Medium", size: 20))
                .foregroundColor(.white)
                .padding()
                .frame(width: 250, height: 50)
                .background(Color.blue)
                .cornerRadius(5)
        }
    }
}
然后添加以下位置管理器类:

class LocationManager: NSObject, ObservableObject {
    private let locationManager = CLLocationManager()
    var authorisationStatus: CLAuthorizationStatus = .notDetermined {
        willSet {
            objectWillChange.send()
        }
    }
    
    var showResult = false {
        willSet {
            objectWillChange.send()
            notificationManager.requestPush()
        }
    }
    
    var notificationManager = NotificationManager()
    
    override init() {
        super.init()
        self.locationManager.delegate = self
    }

    public func request() {
        self.locationManager.requestWhenInUseAuthorization()
    }
}

extension LocationManager: CLLocationManagerDelegate {

    func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
        self.authorisationStatus = status
        
        if (status != .notDetermined) {
            self.showResult = true
        }
    }
    
}
以及以下通知管理器:

class NotificationManager : NSObject, ObservableObject {
    
    @Published var allowedNotifications = false
    @Published var showResult = false

    func requestPush() {
        let center = UNUserNotificationCenter.current()
        
        center.requestAuthorization(options: [.alert, .badge, .sound]) { (success, error) in
            if success {
                DispatchQueue.main.async {
                    self.allowedNotifications = true
                }
            } else if let error = error {
                print(error.localizedDescription)
            } else {
            }
            
            DispatchQueue.main.async {
                self.showResult = true
            }
        }
    }
}
我使用
观察对象
。位置和通知管理器充当
可观察对象
。当状态更新时,视图的图标也相应更新。问题是顺序,一个接一个地调用。这就是为什么必须将NotificationManager传递给LocationManager的原因。完成后,位置管理器将调用通知

顺便说一句,屏幕看起来很棒。这个图标真的很酷!ö

编辑:

下面是加载推送通知初始状态的更新

在NotificationManager内部添加以下
init()
方法

override init() {
    super.init()
    
    let center = UNUserNotificationCenter.current()
    center.getNotificationSettings { (settings) in
        if(settings.authorizationStatus == .authorized)
        {
            self.allowedNotifications = true
            self.showResult = true
        }
        else if (settings.authorizationStatus == .denied)
        {
            self.allowedNotifications = false
            self.showResult = true
        }
    }
}

发生这种情况的原因是位置和通知在DispatchQueueok谢谢,Davidev,但是您能帮助我如何使用该DispatchQueue吗?发生这种情况的原因是位置和通知在DispatchQueueok谢谢,Davidev,但你能帮我如何使用这个调度队列吗?哇,这很酷,谢谢David,真的很感激)但只有当用户允许访问位置和通知时,这才有效,如果用户不允许,那么它将不会显示所选的请求结果,非常感谢您使用图标和屏幕查看我的解决方案,我很高兴您喜欢它,Баааааааааааааааа1072。谢谢你的回复。如果我找到了解决方案,我会再次检查并编辑/返回给你。太棒了嗨,大卫,我发现了一个有趣的错误,不知道如何修复它。问题是,当我移动到通知权限,然后不允许它,然后复选标记的图像没有出现,例如,用户将关闭应用程序,然后再次打开它,它只显示位置复选标记。请帮助)哇,这很酷,谢谢David,真的很感谢)但只有当用户允许访问位置和通知时,这才有效,如果用户不允许,那么它就不会显示所选的请求结果,真的感谢您使用图标和屏幕查看我的解决方案,我很高兴您喜欢它, Дякую Ласкаво просимо. 谢谢你的回复。如果我找到了解决方案,我会再次检查并编辑/返回给你。太棒了嗨,大卫,我发现了一个有趣的错误,不知道如何修复它。问题是,当我移动到通知权限,然后不允许它,然后复选标记的图像没有出现,例如,用户将关闭应用程序,然后再次打开它,它只显示位置复选标记。(请帮忙)