This is the second and last section I am battling with converting Swift 2 to Swift 3
The old working code was
func calculateSegmentDirections(index: Int,
time: NSTimeInterval, routes: [MKRoute]) {
let request: MKDirectionsRequest = MKDirectionsRequest()
request.source = locationArray[index].mapItem
request.destination = locationArray[index+1].mapItem
request.requestsAlternateRoutes = true
request.transportType = .Automobile
let directions = MKDirections(request: request)
directions.calculateDirectionsWithCompletionHandler ({
(response: MKDirectionsResponse?, error: NSError?) in
if let routeResponse = response?.routes {
let quickestRouteForSegment: MKRoute =
routeResponse.sort({$0.expectedTravelTime <
$1.expectedTravelTime})[0]
var timeVar = time
var routesVar = routes
routesVar.append(quickestRouteForSegment)
timeVar += quickestRouteForSegment.expectedTravelTime
if index+2 < self.locationArray.count {
self.calculateSegmentDirections(index+1, time: timeVar, routes: routesVar)
} else {
self.showRoute(routesVar, time: timeVar)
self.hideActivityIndicator()
}
} else if let _ = error {
let alert = UIAlertController(title: nil,
message: "Directions not available.", preferredStyle: .Alert)
let okButton = UIAlertAction(title: "OK",
style: .Cancel) { (alert) -> Void in
self.navigationController?.popViewControllerAnimated(true)
}
alert.addAction(okButton)
self.presentViewController(alert, animated: true,
completion: nil)
}
})
}
The converted code is
func calculateSegmentDirections(index: Int,
time: NSTimeInterval, routes: [MKRoute]) {
let request: MKDirectionsRequest = MKDirectionsRequest()
request.source = locationArray[index].mapItem
request.destination = locationArray[index+1].mapItem
request.requestsAlternateRoutes = true
request.transportType = .Automobile
let directions = MKDirections(request: request)
directions.calculateDirectionsWithCompletionHandler ({
(response: MKDirectionsResponse?, error: NSError?) in
if let routeResponse = response?.routes {
let quickestRouteForSegment: MKRoute =
routeResponse.sort({$0.expectedTravelTime <
$1.expectedTravelTime})[0]
var timeVar = time
var routesVar = routes
routesVar.append(quickestRouteForSegment)
timeVar += quickestRouteForSegment.expectedTravelTime
if index+2 < self.locationArray.count {
self.calculateSegmentDirections(index+1, time: timeVar, routes: routesVar)
} else {
self.showRoute(routesVar, time: timeVar)
self.hideActivityIndicator()
}
} else if let _ = error {
let alert = UIAlertController(title: nil,
message: "Directions not available.", preferredStyle: .Alert)
let okButton = UIAlertAction(title: "OK",
style: .Cancel) { (alert) -> Void in
self.navigationController?.popViewControllerAnimated(true)
}
alert.addAction(okButton)
self.presentViewController(alert, animated: true,
completion: nil)
}
})
}
It throws an error on the line
directions.calculateDirectionsWithCompletionHandler ({
The error is
Cannot convert value of type '(MKDirectionsResponse?, NSError?) -> ()' to expected argument type 'MKDirectionsHandler' (aka '(Optional, Optional) -> ()')
If anyone can help me I would be very thankful!!
NSError was renamed to Error in Swift 3.0 This may fix your issue.
This code compiles for me:
func calculateSegmentDirections(index: Int,
time: TimeInterval, routes: [MKRoute]) {
let request: MKDirectionsRequest = MKDirectionsRequest()
request.source = locationArray[index].mapItem
request.destination = locationArray[index+1].mapItem
request.requestsAlternateRoutes = true
request.transportType = .automobile
let directions = MKDirections(request: request)
directions.calculate (completionHandler: {
(response: MKDirectionsResponse?, error: Error?) in
if let routeResponse = response?.routes {
let quickestRouteForSegment: MKRoute =
routeResponse.sorted(by: {$0.expectedTravelTime <
$1.expectedTravelTime})[0]
var timeVar = time
var routesVar = routes
routesVar.append(quickestRouteForSegment)
timeVar += quickestRouteForSegment.expectedTravelTime
if index+2 < self.locationArray.count {
self.calculateSegmentDirections(index+1, time: timeVar, routes: routesVar)
} else {
self.showRoute(routesVar, time: timeVar)
self.hideActivityIndicator()
}
} else
if let _ = error {
let alert = UIAlertController(title: nil,
message: "Directions not available.", preferredStyle: .alert)
let okButton = UIAlertAction(title: "OK",
style: .Cancel) { (alert) -> Void in
self.navigationController?.popViewControllerAnimated(true)
}
alert.addAction(okButton)
self.presentViewController(alert, animated: true,
completion: nil)
}
})
}
Related
I am trying to make a Graph API call after getting the access token but not able to make the graph API call function.
Facing the error in calling the function, actually I don't have an idea about the HTTP response but I need a user credentials for login and the logout functions, if suppose I got a user credentials means I have to send the data's from login function to logout function.
struct FieldUIViewRepresentable : UIViewControllerRepresentable{
func makeUIViewController(context: Context) -> some UIViewController {
let log = loginviewcontroller()
return log
}
func updateUIViewController(_ uiViewController: UIViewControllerType, context: Context) {
}
}
class loginviewcontroller : UIViewController,UIWindowSceneDelegate{
var lableText : String = "default Login"
var account : MSALAccount? = nil
let kAuthority = "https://login.microsoftonline.com/common"
let kGraphEndpoint = "https://graph.microsoft.com/"
var accessToken : String = ""
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .yellow
let button = UIButton(frame: CGRect(x: 100, y: 100, width: 200, height: 60))
button.setTitle("Login click", for: .normal)
button.setTitleColor(.white, for: .normal)
button.backgroundColor = .blue
button.addTarget(self, action: #selector(login), for: .touchUpInside)
self.view.addSubview(button)
let button2 = UIButton(frame: CGRect(x: 100, y: 180, width: 200, height: 60))
button2.setTitle("Logout", for: .normal)
button2.setTitleColor(.white, for: .normal)
button2.backgroundColor = .red
button2.addTarget(self, action: #selector(logout), for: .touchUpInside)
self.view.addSubview(button2)
}
#objc func login(){
let config = MSALPublicClientApplicationConfig(clientId: "0f166c0f-55e1-4de1-b6fe-e0c35c331f4b")
let scopes = [""]
if let application = try? MSALPublicClientApplication(configuration: config) {
let viewController = self
let webviewParameters = MSALWebviewParameters(authPresentationViewController: viewController)
let interactiveParameters = MSALInteractiveTokenParameters(scopes: scopes, webviewParameters: webviewParameters)
application.acquireToken(with: interactiveParameters, completionBlock: { (result, error) in
guard let authResult = result, error == nil else {
print("The auth result is \(error!)")
print("Auth result localized error \(error!.localizedDescription)")
return
}
print("Auth Result is \(authResult.account)")
self.account = authResult.account
let accessToken = authResult.accessToken
self.accessToken = accessToken
self.getContentWithToken()
print("The access token is \(accessToken)")
let accountIdentifier = authResult.account.identifier
print("Account Identifier \(String(describing: accountIdentifier))")
})
}
else {
print("Unable to create application.")
}
}
func getContentWithToken() {
print("get content with token function invokes")
// Specify the Graph API endpoint
let graphURI = getGraphEndpoint()
let url = URL(string: graphURI)
var request = URLRequest(url: url!)
request.setValue("Bearer \(self.accessToken)", forHTTPHeaderField: "Authorization")
URLSession.shared.dataTask(with: request) { data, response, error in
if let error = error {
return
}
guard let result = try? JSONSerialization.jsonObject(with: data!, options: []) else {
return
}
}.resume()
}
func getGraphEndpoint() -> String {
return kGraphEndpoint.hasSuffix("/") ? (kGraphEndpoint + "v1.0/me/") : (kGraphEndpoint + "/v1.0/me/");
}
#objc func logout(){
let account = self.account ?? nil //* account retrieved above
let config = MSALPublicClientApplicationConfig(clientId: "0f166c0f-55e1-4de1-b6fe-e0c35c331f4b")
let scopes = [""]
let application = try? MSALPublicClientApplication(configuration: config)
let viewController = self
let webviewParameters = MSALWebviewParameters(authPresentationViewController: viewController)
let signoutParameters = MSALSignoutParameters(webviewParameters: webviewParameters)
signoutParameters.signoutFromBrowser = false
application?.signout(with: account!, signoutParameters: signoutParameters, completionBlock: {(success, error) in
if let error = error {
// Signout failed
return
}
print("Signout is Completed")
// Sign out completed successfully
})
}
}
I want to build the video call function in my app and i decided to choose Sinch framework. But when i press the call, seem the localView can not track. Please help me how to fix this. Thank a lot. Here is my code get error:
func videoController() -> SINVideoController {
let appDel = UIApplication.shared.delegate as! AppDelegate
return (appDel.client?.videoController())!
}
I got this error in return line:
Thread 1: EXC_BREAKPOINT (code=1, subcode=0x102bcc740)
Here is my code:
override func viewDidLoad() {
super.viewDidLoad()
sinCall?.delegate = self
playSound()
if sinCall?.direction == SINCallDirection.incoming {
lbReceiverName.text = "Đang gọi"
_ = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(updateLabelForReceiver), userInfo: nil, repeats: true)
if let id = senderName {
databaseRefenrence.child("Users").child("\(id)").observeSingleEvent(of: .value, with: { (snapshot) in
if let dict = snapshot.value as? [String : Any] {
self.lbDangGoi.text = dict["Name"] as? String
}
})
}
localView.isHidden = false
btAccept.isHidden = false
btDecline.isHidden = false
btEnd.isHidden = true
} else {
_ = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(updateLabelForSender), userInfo: nil, repeats: true)
if let name = receiverName {
lbReceiverName.text = name
}
localView.isHidden = false
btAccept.isHidden = true
btDecline.isHidden = true
btEnd.isHidden = false
}
if sinCall?.details.isVideoOffered == true {
localView.addSubview((videoController().localView())!)
}
}
func callDidAddVideoTrack(_ call: SINCall!) {
remoteView.addSubview((videoController().remoteView())!)
}
How i can handle error in completion block if get error from server side.Here is object mapper class for login.
class Login: Mappable {
var result: LoginData?
var success: Bool?
var error: String?
required init?(map: Map){
}
func mapping(map: Map) {
result <- map["data"]
success <- map["success"]
error <- map["error"]
}
}
class LoginData: Mappable {
var name: String?
var title: String?
var token: String?
var imageUrl: String?
required init?(map: Map){
}
func mapping(map: Map) {
name <- map["name"]
title <- map["title"]
token <- map["token"]
name <- map["name"]
imageUrl <- map["imageUrl"]
}
}
Here is my api calling from view controller.
func loginMethod(){
let postData = ["username":loginDict.object(forKey: KUserUserId) as! String,
"password": loginDict.object(forKey: KUserPass) as! String]
userLoginHttp(parameters: postData){ completion in
self.getUserLoginResponse(result: completion)
}
}
func getUserLoginResponse(result: LoginData) {
// Here i do further
}
This is Network class mthod from where i fire the service
//User login web service
func userLoginHttp(parameters:Parameters, completion:#escaping (_
result:LoginData)->()) {
let defaultObject = UserDefaults.standard
var headerToken = String()
if let x = defaultObject.object(forKey: KDeviceToken)
{
headerToken = x as! String
}
else{
headerToken = ""
}
let headers = ["fcmToken": headerToken]
Alamofire.request(KLoginUrl, method: .post, parameters: parameters,encoding: JSONEncoding.default, headers: headers)
.validate()
.responseObject{ (response: DataResponse<Login>) in
switch response.result{
case .success:
let value = response.result.value
completion((value?.result)!)
case .failure(let error):
print(error.localizedDescription)
}
}
}
So how i can handle error in my view controller completion block?
you can just create another handler for errors and call it in error case
func userLoginHttp(parameters:Parameters,
completion:#escaping (_ result:LoginData)->(),
errorHandler:#escaping (_ result:Error,_ statusCode:Int?)->()//error handler
) {
let defaultObject = UserDefaults.standard
var headerToken = String()
if let x = defaultObject.object(forKey: KDeviceToken)
{
headerToken = x as! String
}
else{
headerToken = ""
}
let headers = ["fcmToken": headerToken]
Alamofire.request(KLoginUrl, method: .post, parameters: parameters,encoding: JSONEncoding.default, headers: headers)
.validate()
.responseObject{ (response: DataResponse<Login>) in
switch response.result{
case .success:
let value = response.result.value
completion((value?.result)!)
case .failure(let error):
errorHandler(error,response.response?.statusCode)//call error handler
print(response.response?.statusCode)
print(error.localizedDescription)
}
}
}
usage
func loginMethod(){
let postData = ["username":loginDict.object(forKey: KUserUserId) as! String,
"password": loginDict.object(forKey: KUserPass) as! String]
userLoginHttp(
parameters: postData,
completion:{ completion in
self.getUserLoginResponse(result: completion)
},
errorHandler:{ error,code in
//do your error stuff
})
}
func getUserLoginResponse(result: LoginData) {
// Here i do further
}
I am trying to use youtube api in ios swift, and following this tutorial
http://www.appcoda.com/youtube-api-ios-tutorial/
HTTP Status Code = 403
Error while loading channel details: nil
I'm using swift 3
var urlString = "https://www.googleapis.com/youtube/v3/search?part=snippet&q=\(textField.text)&type=\(type)&key=\(apiKey)"
urlString = urlString.addingPercentEncoding(withAllowedCharacters: CharacterSet.urlQueryAllowed)!
// Create a NSURL object based on the above string.
let targetURL = URL(string: urlString)
// Get the results.
performGetRequest(targetURL, completion: { (data, HTTPStatusCode, error) -> Void in
if HTTPStatusCode == 200 && error == nil {
// Convert the JSON data to a dictionary object.
do {
let resultsDict = try JSONSerialization.jsonObject(with: data!, options: []) as! Dictionary<String, AnyObject>
// Get all search result items ("items" array).
let items: Array<Dictionary<String, AnyObject>> = resultsDict["items"] as! Array<Dictionary<String, AnyObject>>
// Loop through all search results and keep just the necessary data.
for i in 0 ..< items.count {
let snippetDict = items[i]["snippet"] as! Dictionary<String, AnyObject>
// Gather the proper data depending on whether we're searching for channels or for videos.
if self.segDisplayedContent.selectedSegmentIndex == 0 {
// Keep the channel ID.
self.desiredChannelsArray.append(snippetDict["channelId"] as! String)
}
else {
// Create a new dictionary to store the video details.
var videoDetailsDict = Dictionary<String, AnyObject>()
videoDetailsDict["title"] = snippetDict["title"]
videoDetailsDict["thumbnail"] = ((snippetDict["thumbnails"] as! Dictionary<String, AnyObject>)["default"] as! Dictionary<String, AnyObject>)["url"]
videoDetailsDict["videoID"] = (items[i]["id"] as! Dictionary<String, AnyObject>)["videoId"]
// Append the desiredPlaylistItemDataDict dictionary to the videos array.
self.videosArray.append(videoDetailsDict)
// Reload the tableview.
self.tblVideos.reloadData()
}
}
} catch {
print(error)
}
// Call the getChannelDetails(…) function to fetch the channels.
if self.segDisplayedContent.selectedSegmentIndex == 0 {
self.getChannelDetails(true)
}
}
else {
print("HTTP Status Code = \(HTTPStatusCode)")
print("Error while loading channel videos: \(error)")
}
// Hide the activity indicator.
self.viewWait.isHidden = true
})
return true
}
// MARK: Custom method implementation
func performGetRequest(_ targetURL: URL!, completion: #escaping (_ data: Data?, _ HTTPStatusCode: Int, _ error: NSError?) -> Void) {
// let request = NSMutableURLRequest(url: targetURL)
// request.httpMethod = "GET"
var request = URLRequest(url: targetURL)
request.httpMethod = "GET"
let sessionConfiguration = URLSessionConfiguration.default
let session = URLSession(configuration: sessionConfiguration)
/* let task = session.dataTask(with: request, completionHandler: { (data: Data?, response: URLResponse?, error: NSError?) -> Void in
DispatchQueue.main.async(execute: { () -> Void in
completion(data, (response as! HTTPURLResponse).statusCode, error)
})
} as! (Data?, URLResponse?, Error?) -> Void)*/
/* let task = session.dataTask(with: request, completionHandler: ({ (data: Data?, response: URLResponse?, error: NSError?) -> Void in
DispatchQueue.main.async(execute: { () -> Void in
completion(data as Data?, (response as! HTTPURLResponse).statusCode, error)
})
} as! (Data?, URLResponse?, Error?) -> Void))*/
let task = session.dataTask(with: request) { data, response, error in DispatchQueue.main.async { completion(data, (response as! HTTPURLResponse).statusCode, error as? NSError) } }
task.resume()
}
First of all the JSON dictionary representation in Swift 3 is [String:Any] (aka Dictionary<String,Any>)
Second of all in Swift 3 all parameter labels in closures have been removed
func performGetRequest(_ targetURL: URL, completion: #escaping (Data?, Int, NSError?) -> Void) {
Do not use implicit unwrapped optionals for method parameter types. Either use regular optional (?) or non-optional.
Error 403 means Forbidden Access. Make sure you have the correct apiKey from google/youtube developer.
I also used the appcoda youtube api tutorial (which is in Swift 2 I think) and this is a working version of mine for swift 3.
func getVideosForChannelAtIndex() {
let urlString = "https://www.googleapis.com/youtube/v3/playlistItems?part=snippet&playlistId=\(playlistID)&maxResults=\(maxResults)&key=\(apiKey)"
// Create a NSURL object based on the above string.
let targetURL = URL(string: urlString)
// Fetch the playlist from Google.
performGetRequest(targetURL!) { (data, HTTPStatusCode, error) -> Void in
if HTTPStatusCode == 200 && error == nil {
do {
self.videos = []
// Convert the JSON data into a dictionary.
let resultsDict = try JSONSerialization.jsonObject(with: data!, options: []) as! Dictionary<AnyHashable, Any>
// Get all playlist items ("items" array).
let items:Array<Dictionary<AnyHashable, Any>> = resultsDict["items"] as! Array<Dictionary<AnyHashable, Any>>
// Use a loop to go through all video items.
// for var i=0; i<items.count; ++i
for i in 0 ..< items.count {
let playlistSnippetDict = (items[i] as Dictionary<AnyHashable, Any>)["snippet"] as! Dictionary<AnyHashable, Any>
let video = Video()
video.title = playlistSnippetDict["title"] as? String
// video.thumbnail =
video.videoId = (playlistSnippetDict["resourceId"] as? Dictionary<AnyHashable, Any>)?["videoId"] as? String
guard let thumbnail = ((playlistSnippetDict["thumbnails"] as? Dictionary<AnyHashable, Any>)?["high"] as? Dictionary<AnyHashable, Any>)?["url"] as? String else {
video.thumbnail = UIImage(named: "Icon1024x1024")
return
}
guard let url:URL? = URL(string: thumbnail), let data:Data? = try? Data(contentsOf: url!) else {
video.thumbnail = UIImage(named: "Icon1024x1024")
return
}
if let dataImage = data {
video.thumbnail = UIImage(data: dataImage)
} else {
video.thumbnail = UIImage(named: "Icon1024x1024")
}
self.videos.append(video)
// Reload the tableview.
self.tblVideos.reloadData()
}
} catch {
print("json error: \(error)")
}
} else {
print("")
print("HTTP Status Code = \(HTTPStatusCode)")
print("")
//Show alertDialog here with Error
print("Error while loading videos: \(error?.localizedDescription)")
let alert = UIAlertView(title: "Oops!", message: error?.localizedDescription, delegate: self, cancelButtonTitle: "OK")
alert.show()
}
// Hide the activity indicator.
self.viewWait.isHidden = true
}
}
This is for the performGetRequest
func performGetRequest(_ targetURL: URL, completion: #escaping (_ data: Data?, _ HTTPStatusCode: Int?, _ error: Error?) -> Void) {
var request = URLRequest(url: targetURL)
request.httpMethod = "GET"
let sessionConfiguration = URLSessionConfiguration.default
let session = URLSession(configuration: sessionConfiguration)
let task = session.dataTask(with: request) { data, response, error in
DispatchQueue.main.async(execute: {
completion(data, (response as? HTTPURLResponse)?.statusCode, error)
})
}
task.resume()
}
I use a general CoreData query method in my project.
func query(table: String, searchPredicate: NSPredicate) -> [AnyObject]
{
let context = app.managedObjectContext
let fetchRequest = NSFetchRequest(entityName: table)
fetchRequest.predicate = searchPredicate
let results = try! context.fetch(fetchRequest)
return results
}
In Swift 3 this doesn't work. I found this on Apple's web site:
func findAnimals()
{
let request: NSFetchRequest<Animal> = Animal.fetchRequest
do
{
let searchResults = try context.fetch(request)
... use(searchResults) ...
}
catch
{
print("Error with request: \(error)")
}
}
Using the Apple example, how would I pass Animal in to the method as a parameter to make findAnimals more generic?
I haven't tried this but I think something like this would work...
func findCoreDataObjects<T: NSManagedObject>() -> [T] {
let request = T.fetchRequest
do
{
let searchResults = try context.fetch(request)
... use(searchResults) ...
}
catch
{
print("Error with request: \(error)")
}
}
You have to make the entire function generic and so you have to tell it what type T is when calling it.
someObject.findCoreDataObjects<Animal>()
I think that should do the job. Not entirely certain though as I'm new to generics myself :D
How about this.
func query<T: NSManagedObject>(table: String, searchPredicate: NSPredicate) -> [T] {
let context = app.managedObjectContext
let fetchRequest: NSFetchRequest<T> = NSFetchRequest(entityName: table)
fetchRequest.predicate = searchPredicate
let results = try! context.fetch(fetchRequest)
return results
}
Here is the final result that may help someone:
import Foundation
import Cocoa
func addRecord<T: NSManagedObject>(_ type : T.Type) -> T
{
let entityName = T.description()
let context = app.managedObjectContext
let entity = NSEntityDescription.entity(forEntityName: entityName, in: context)
let record = T(entity: entity!, insertInto: context)
return record
}
func recordsInTable<T: NSManagedObject>(_ type : T.Type) -> Int
{
let recs = allRecords(T.self)
return recs.count
}
func allRecords<T: NSManagedObject>(_ type : T.Type, sort: NSSortDescriptor? = nil) -> [T]
{
let context = app.managedObjectContext
let request = T.fetchRequest()
do
{
let results = try context.fetch(request)
return results as! [T]
}
catch
{
print("Error with request: \(error)")
return []
}
}
func query<T: NSManagedObject>(_ type : T.Type, search: NSPredicate?, sort: NSSortDescriptor? = nil, multiSort: [NSSortDescriptor]? = nil) -> [T]
{
let context = app.managedObjectContext
let request = T.fetchRequest()
if let predicate = search
{
request.predicate = predicate
}
if let sortDescriptors = multiSort
{
request.sortDescriptors = sortDescriptors
}
else if let sortDescriptor = sort
{
request.sortDescriptors = [sortDescriptor]
}
do
{
let results = try context.fetch(request)
return results as! [T]
}
catch
{
print("Error with request: \(error)")
return []
}
}
func deleteRecord(_ object: NSManagedObject)
{
let context = app.managedObjectContext
context.delete(object)
}
func deleteRecords<T: NSManagedObject>(_ type : T.Type, search: NSPredicate? = nil)
{
let context = app.managedObjectContext
let results = query(T.self, search: search)
for record in results
{
context.delete(record)
}
}
func saveDatabase()
{
let context = app.managedObjectContext
do
{
try context.save()
}
catch
{
print("Error saving database: \(error)")
}
}
Call it with:
let name = "John Appleseed"
let newContact = addRecord(Contact.self)
newContact.contactNo = 1
newContact.contactName = name
let contacts = query(Contact.self, search: NSPredicate(format: "contactName == %#", name))
for contact in contacts
{
print ("Contact name = \(contact.contactName), no = \(contact.contactNo)")
}
deleteRecords(Contact.self, search: NSPredicate(format: "contactName == %#", name))
recs = recordsInTable(Contact.self)
print ("Contacts table has \(recs) records")
saveDatabase()
I use that way in my projects:
static func retrieveRecords<T: NSManagedObject>(table: String, sortDescriptorKey: NSSortDescriptor? = nil) -> [T] {
do {
let fetchRequest: NSFetchRequest<T> = NSFetchRequest(entityName: table)
fetchRequest.sortDescriptors = [sortDescriptorKey!]
let results = try context.fetch(fetchRequest)
print("\(results)")
return results
} catch let error {
print("Could not fetch \(error.localizedDescription)")
return []
}
}
And to call it:
personen = retrieveRecords(table: "Person", sortDescriptorKey: NSSortDescriptor(key: #keyPath(Person.nachname), ascending: true, selector: #selector(NSString.localizedCompare)))