I inherit from a protocol that implements in its extension those functions, that should not be required by the adopting class and instead I get those errors.
Could someone explain why those errors appear and how to fix it.
I inherit from a protocol that implements in its extension those functions, that should not be required by the adopting class and instead I get those errors.
Could someone explain why those errors appear and how to fix it.
Could you show the complete protocol definition and its extension ?
Could this article may be useful? https://medium.com/@leandromperez/protocol-extensions-gotcha-9ef1a42c83b6
This is the protocol:
@preconcurrency import CoreLocation
import MapKit
import Foundation
import UserNotifications
typealias SpeedTestCompletionHandler = (_ megabytesTransferred: Float? , _ bytesTotal: Float?, _ error: Error?, _ completed: Bool) -> Void
struct ElevationResponse: Decodable{
let elevation: Double
let location: [String: Double]
let resolution: Double
}
extension String {
static func randomString(length: Int = 20) -> String {
let letters : NSString = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
let len = UInt32(letters.length)
var randomString = ""
for _ in 0 ..< length {
let rand = arc4random_uniform(len)
var nextChar = letters.character(at: Int(rand))
randomString += NSString(characters: &nextChar, length: 1) as String
}
return randomString
}
}
protocol TemplateBackgroundLocationUpdate: NSObject, CLLocationManagerDelegate, URLSessionDelegate {
var locationManager: CLLocationManager {get set}
var speedTestCompletionBlock : SpeedTestCompletionHandler? {get set}
var submitCompletion:((Data?, Error?)->Void)? {get set}
var bytesExchanged: Int? {get set}
var session:Foundation.URLSession? {get set}
typealias emptyClosure = (() -> Void)
var widgetHandler: emptyClosure? {get set}
var standardSession: URLSession {get set}
var previousTime: Date {get set}
var oldLocation: CLLocation! {get set}
var date: Date {get set}
var newDate: Date {get set}
init()
func loggedConnect(to urlRequest: URLRequest, interval timeout: TimeInterval, withCompletionBlock: @escaping SpeedTestCompletionHandler)
func locationManagerDidChangeAuthorization(_ manager: CLLocationManager)
func locateUserAtLocation(_ location: CLLocation, moved:Bool)
func locateUserAtHeading(heading: CLLocationDirection)
func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data)
}
extension TemplateBackgroundLocationUpdate {
public init(){
self.init()
locationManager=CLLocationManager()
#if hd || express
NotificationCenter.default.addObserver(self, selector: #selector(TemplateBackgroundLocationUpdate.appWillResignActive(_:)), name: NSNotification.Name.UIApplicationWillResignActive, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(TemplateBackgroundLocationUpdate.appWillEnterForeground(_:)), name: NSNotification.Name.UIApplicationWillEnterForeground, object: nil)
#endif
self.locationManager.delegate = self;
self.locationManager.startUpdatingLocation()
locationManager.pausesLocationUpdatesAutomatically = true
let configuration=URLSessionConfiguration.background(withIdentifier: String.randomString())
configuration.sessionSendsLaunchEvents=true
standardSession = Foundation.URLSession.shared
previousTime = Date()
oldLocation=CLLocation()
date=Date()
newDate=Date()
}
func application(
_ application: UIApplication,
handleEventsForBackgroundURLSession identifier: String,
completionHandler: @escaping () -> Void) {
Task.init{
await GeoreferenceQueue.shared.setBackgroundCompletionHandler(completionHandler)
}
}
func loggedConnect(to urlRequest: URLRequest, interval timeout: TimeInterval, withCompletionBlock: @escaping SpeedTestCompletionHandler){
bytesExchanged = 0
speedTestCompletionBlock = withCompletionBlock
let configuration = URLSessionConfiguration.default
configuration.timeoutIntervalForResource = timeout
session = URLSession.init(configuration: configuration, delegate: self, delegateQueue: nil)
session!.dataTask(with: urlRequest).resume()
}
func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive response: URLResponse, completionHandler: @escaping (URLSession.ResponseDisposition) -> Void){
completionHandler(.allow)
}
func urlSession(_ session: URLSession, task: URLSessionTask, didSendBodyData bytesSent: Int64, totalBytesSent: Int64, totalBytesExpectedToSend: Int64){
speedTestCompletionBlock?(Float(totalBytesSent), Float(totalBytesExpectedToSend), nil, false)
}
func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data) {
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
if let JSONString = String(data: data, encoding: String.Encoding.utf8)
{
print(JSONString)
}
}
func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
print("did complete with error \(String(describing: error?.localizedDescription))")
speedTestCompletionBlock?(0, 0, nil, true)
}
func urlSessionDidFinishEvents(forBackgroundURLSession session: URLSession){
Task.init {
await GeoreferenceQueue.shared.executeCompletionHandler()
}
}
func backgroundCompleted(data: Data?, error: Error?=nil){
print("top")
}
public func urlSession(_ session: URLSession,
downloadTask: URLSessionDownloadTask,
didFinishDownloadingTo location: URL){
do {
//print("location=\(location)")
let data = try Data(contentsOf: location, options: .uncachedRead)
// Hold this file as an NSData and write it to the new location
//submitCompletion?(data, nil)
backgroundCompleted(data: data)
} catch {
backgroundCompleted(data: nil, error: error)
print("could not get data for error \(error)")
}
}
public func locationManagerDidChangeAuthorization(_ manager: CLLocationManager) {
Task.init{
let backgroundLocalizationActive=await GeoreferenceQueue.shared.getBackgroundLocalizationActive()
await MainActor.run {
if CLLocationManager.locationServicesEnabled() {
if manager.authorizationStatus == .authorizedAlways && backgroundLocalizationActive{
if #available(iOS 17.0, *) {
//let backgroundSession=CLBackgroundActivitySession()
} else {
// Fallback on earlier versions
}
self.locationManager.requestAlwaysAuthorization()
self.locationManager.showsBackgroundLocationIndicator=true
//let session=CLServiceSession(autorization: CLServiceSession.AuthorizationRequirement.always
//
} else if (manager.authorizationStatus == .authorizedWhenInUse){
self.locationManager.allowsBackgroundLocationUpdates = false
self.locationManager.desiredAccuracy = 5;
//self.locationManager!.desiredAccuracy=kCLLocationAccuracyBest
self.locationManager.distanceFilter = kCLDistanceFilterNone
self.locationManager.headingFilter = kCLHeadingFilterNone
self.locationManager.pausesLocationUpdatesAutomatically=true;
}
}
}
print("start localizing")
}
}
func locationManager( _ manager: CLLocationManager, didUpdateHeading newHeading: CLHeading) {
let heading = newHeading.trueHeading > 0 ? newHeading.trueHeading : newHeading.magneticHeading
locateUserAtHeading(heading: heading)
}
func handleLocationUpdate(_ newLocation:CLLocation, moved: Bool) async throws { //virtual
}
public func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]){
newDate=Date()
//print("didUpdateLocation")
var moved=false
if let lastLocation=locations.first{
Task.init{
await SettingsActor.shared.setPresentLocation(lastLocation) //valore usato da discendenti
}
let timePast=newDate.timeIntervalSince(date)
if timePast>30 {
moved = lastLocation.distance(from: oldLocation)>50
date=newDate
oldLocation=lastLocation
}
Task.init{
try? await self.handleLocationUpdate(lastLocation, moved: moved)
}
}
}
func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
Task.init{
await MainActor.run{
let title=NSLocalizedString("Your location", comment:"")
let message=String(format:NSLocalizedString( "I am not able to establish your location: please move somewhat possibly in an uncovered area", comment:""), CLLocation().altitude)
let dismiss=NSLocalizedString("Dismiss", comment:"")
let alertController = UIAlertController(title: title, message: message, preferredStyle: .alert)
let cancelAction = UIAlertAction(title: dismiss, style: .cancel) { (action) in
}
alertController.addAction(cancelAction)
}
}
}
#if !limo
func triggerActiveLocationUpdate(_ entering:Bool){ //virtual
}
func appWillResignActive(_ notification: Notification){
triggerActiveLocationUpdate(false)
}
func appWillEnterForeground(_ notification: Notification){
triggerActiveLocationUpdate(true)
}
#endif
func debugNotification(_ message:String){
#if !NDDEBUG
//localNotification(message)
#endif
}
/*public func localNotification(_ message:String){ //for Objective -C
self.localNotification(message, sound:nil, badge:nil)
}*/
func stringUUID()->String{
let strUUID = UUID().uuidString
return strUUID
}
func localNotification(_ title:String, message:String, sound:UNNotificationSound?, badge:Int?, interval:TimeInterval, userInfo: [AnyHashable : Any]?, category:UNNotificationCategory?=nil){
let center = UNUserNotificationCenter.current()
let content = UNMutableNotificationContent()
content.title = title
content.body = message
content.categoryIdentifier = "alarm"
if category != nil{
UNUserNotificationCenter.current().setNotificationCategories([category!])
}
if let isUserInfo=userInfo{
content.userInfo = isUserInfo
}
content.sound = sound
//var dateComponents = DateComponents()
//dateComponents.hour = 10
//dateComponents.minute = 30
//let trigger = UNCalendarNotificationTrigger(dateMatching: dateComponents, repeats: true)
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: interval, repeats: false)
let request = UNNotificationRequest(identifier: UUID().uuidString, content: content, trigger: trigger)
center.add(request)
}
}
Which stubs are added if you accept the proposed addition ?