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 中正确实现不同视图控制器之间的协议和委托?