swift - 我的协议和代表不工作

Posted

技术标签:

【中文标题】swift - 我的协议和代表不工作【英文标题】:swift - My Protocol and Delegate isn't working 【发布时间】:2020-04-06 20:58:20 【问题描述】:

我创建了一个名为 TermProtocol 的协议,其中包含一个名为 gotTerm 的函数。每当用户在我的视图(CategoryView)中按下此按钮时,委托都应该获得回调并运行我设置的代码。在我的例子中,代表将是 AppDelegate。我在应用程序委托中名为 gotTerm 的函数中放置了一条打印语句,以便我可以查看代码是否真的在运行,但我从未在控制台中看到我在打印语句中放入的短语。我认为我的代表没有收到回调。谁能帮帮我?

这是我的代码:

术语协议:

protocol TermProtocol: class
    func gotTerm()

CategoryView.Swift

struct CategoryView: View 
var foodCategory: String
let appDelegate = UIApplication.shared.delegate as? AppDelegate
var delegate: TermProtocol?
var body: some View 
    NavigationView 

            NavigationLink(destination: RestrauntView()) 
                Image("Find Button")
                    .renderingMode(.original)

            .simultaneousGesture(TapGesture().onEnded
                    print("didtapallow 4")
                self.appDelegate!.terms = self.foodCategory
                self.delegate?.gotTerm()
            )
            Spacer()


    



struct CategoryView_Previews: PreviewProvider 
    static var previews: some View 
        CategoryView(foodCategory: "Chinese Food")
    

AppDelegate.swift

import UIKit
import CoreData
import Moya
import Alamofire
import CoreLocation

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate, TermProtocol 


func gotTerm() 
    print("did get term")
            let lat = self.locationService.setup(latOrLong: "lat")
            let long = self.locationService.setup(latOrLong: "long")
            self.locationService.lat = lat
            self.locationService.long = long

    self.loadBusinesses(lat: lat, long: long, theTerm: self.terms)




var theViewModels = [RestrauntListViewModel]()
let locationService = LocationService()
var terms = ""
var categoryView = CategoryView(foodCategory: "indian")
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool 
    // Override point for customization after application launch.
    categoryView.delegate = self


    let dataSource = DataSource()
    print("this is the view models in appDelegate: \(theViewModels)")


    locationService.didChangeStatus =  [weak self] success in
        print("did tap allow 1")
        if success 
            self?.locationService.getLocation()
        
    

    locationService.newLocation =  [weak self] result in
        print("did tap allow 2")
        switch result 
        case .success(let location):
            self?.loadBusinesses(lat: location.coordinate.latitude, long: location.coordinate.longitude, theTerm: "chinese")
        case .failure(let error):
            assertionFailure("Error getting the users location \(error)")
        
    
    locationService.setup(latOrLong: "lat")
    return true

func loadBusinesses (lat: Double, long: Double, theTerm: String) 

           let service = MoyaProvider<YelpService.BusinessProvider>()
           let jsonDecoder = JSONDecoder()

           let restrauntView = RestrauntView()
        let appDelegate = AppDelegate()
           print("The latitude of u is \(lat) and the long of you is \(long)")


           if CLLocationManager.locationServicesEnabled() 

            switch CLLocationManager.authorizationStatus() 
                   case .notDetermined, .restricted, .denied:
                       print("No access")


                   case .authorizedAlways, .authorizedWhenInUse:
                       print("Access")

                       service.request(.search(lat: lat, long: long, term: theTerm))  (result) in
                                       switch result
                                       case.success(let response):
                                           print("yaya")
                                           let root = try? jsonDecoder.decode(Root.self, from: response.data)
                                           let viewModels = root?.businesses.compactMap(RestrauntListViewModel.init)
                                           let dataSource = DataSource()
                                           dataSource.arrayOfImages.removeAll()



                                           for image in viewModels! 

                                                       Alamofire.request(image.imageURL).responseImage  response in
                                                           if let image = response.result.value 
                                                               print("image downloadedline 59 appdelegate")
                                                               dataSource.arrayOfImages.append(image)
                                                               print(dataSource.arrayOfImages)
                                                            else 
                                                               print("ERROR: image does not = response.result.value")
                                                           
                                                       
                                                   

                                           self.theViewModels = (root?.businesses.compactMap(RestrauntListViewModel.init))!


                                           print(" restrauntView.theViewModels is here \(restrauntView.theViewModels)")

                                           print("the constant theViewModels in the appdelegate has \(appDelegate.theViewModels.count) values")

                                       case .failure(let error):
                                           print("Error: \(error)")
                                       
                   

                   @unknown default:
                   break
               



                else 
                   print("Location services are not enabled")
           


       




// MARK: UISceneSession Lifecycle

func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration 
    // Called when a new scene session is being created.
    // Use this method to select a configuration to create the new scene with.
    return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)


func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set<UISceneSession>) 
    // Called when the user discards a scene session.
    // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.
    // Use this method to release any resources that were specific to the discarded scenes, as they will not return.


// MARK: - Core Data stack

lazy var persistentContainer: NSPersistentContainer = 
    /*
     The persistent container for the application. This implementation
     creates and returns a container, having loaded the store for the
     application to it. This property is optional since there are legitimate
     error conditions that could cause the creation of the store to fail.
    */
    let container = NSPersistentContainer(name: "Actrual_Food_Circle")
    container.loadPersistentStores(completionHandler:  (storeDescription, error) in
        if let error = error as NSError? 
            // Replace this implementation with code to handle the error appropriately.
            // fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.

            /*
             Typical reasons for an error here include:
             * The parent directory does not exist, cannot be created, or disallows writing.
             * The persistent store is not accessible, due to permissions or data protection when the device is locked.
             * The device is out of space.
             * The store could not be migrated to the current model version.
             Check the error message to determine what the actual problem was.
             */
            fatalError("Unresolved error \(error), \(error.userInfo)")
        
    )
    return container
()

// MARK: - Core Data Saving support

func saveContext () 
    let context = persistentContainer.viewContext
    if context.hasChanges 
        do 
            try context.save()
         catch 
            // Replace this implementation with code to handle the error appropriately.
            // fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
            let nserror = error as NSError
            fatalError("Unresolved error \(nserror), \(nserror.userInfo)")
        
    



【问题讨论】:

你永远不会给delegate属性赋值,所以它是nil。您真的不应该以这种方式使用您的应用程序委托。您可能想要创建一个模型对象,并且由于您使用的是 SwiftUI,因此请使用发布对象和可观察对象 这不是实现委托的正确方法,但您仍然可以通过以下方式访问您的方法:self.appDelegate!.gotTerm() 而不是 self.delegate?.gotTerm() 【参考方案1】:

我将首先说明您不应该在 SwiftUI 中以这种方式使用委托和闭包。这是使用 SwiftUI 的干净 MVVM 架构的一个很好的介绍 - https://nalexn.github.io/clean-architecture-swiftui/。

我相信您会想要添加 ViewModel 来处理应用程序中的这些状态。

回到回答您的问题 - 我认为在这种情况下添加 closures 将是最快(不一定正确)的解决方案:

struct ContentView: View 
    var gotTermCallback: (()->())?
    var body: some View 
        NavigationView 
            NavigationLink(destination: Text("test")) 
                ...
                .simultaneousGesture(TapGesture().onEnded
                    ...
                    self.gotTermCallback?()
                )
                ...
        
    

然后您可以通过简单地调用以下代码将其添加到某种处理程序或副作用处理程序中:

var contentView: ContentView = ContentView()
contentView.gotTermCallback = 
  print("[DEBUG] - terms callback")

【讨论】:

以上是关于swift - 我的协议和代表不工作的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Swift 中正确实现不同视图控制器之间的协议和委托?

支持的协议和封装协议

如何在 Swift 中翻译 @synthesize 协议变量?

协议和代表不起作用..我做错了啥?

说说开发中常用的USART的协议和工作原理

Swift3 - 扩展类型集合的问题