Updating the label with current heart rate (swift and watch kit) - ios

When you click on the button the current heart rate should be captured and the label should be updated. But, I do not understand why the label won't get updated with the heart rate value. I do not know what is wrong here.
I am still a very beginner in terms of swift and watch kit. I hope anyone can help me out.
Thank you very much.
Below you can see the code. I have also added the authorization part into the AppDelegate.swift file.
import WatchKit
import Foundation
import HealthKit
class InterfaceController: WKInterfaceController {
#IBOutlet weak var label: WKInterfaceLabel!
#IBOutlet weak var button: WKInterfaceButton!
var isRecording = false
//For workout session
let healthStore = HKHealthStore()
var session: HKWorkoutSession?
var currentQuery: HKQuery?
override func awake(withContext context: Any?) {
super.awake(withContext: context)
// Configure interface objects here.
}
override func willActivate() {
// This method is called when watch view controller is about to be visible to user
super.willActivate()
//Check HealthStore
guard HKHealthStore.isHealthDataAvailable() == true else {
print("Health Data Not Avaliable")
return
}
}
override func didDeactivate() {
// This method is called when watch view controller is no longer visible
super.didDeactivate()
}
#IBAction func btnPressed() {
if(!isRecording){
let stopTitle = NSMutableAttributedString(string: "Stop Recording")
stopTitle.setAttributes([NSAttributedString.Key.foregroundColor: UIColor.red], range: NSMakeRange(0, stopTitle.length))
button.setAttributedTitle(stopTitle)
isRecording = true
startWorkout() //Start workout session/healthkit streaming
}else{
let exitTitle = NSMutableAttributedString(string: "Start Recording")
exitTitle.setAttributes([NSAttributedString.Key.foregroundColor: UIColor.green], range: NSMakeRange(0, exitTitle.length))
button.setAttributedTitle(exitTitle)
isRecording = false
healthStore.end(session!)
label.setText("Heart Rate")
}
}
}
extension InterfaceController: HKWorkoutSessionDelegate{
func workoutSession(_ workoutSession: HKWorkoutSession, didChangeTo toState: HKWorkoutSessionState, from fromState: HKWorkoutSessionState, date: Date) {
switch toState {
case .running:
print(date)
if let query = heartRateQuery(date){
self.currentQuery = query
healthStore.execute(query)
}
//Execute Query
case .ended:
//Stop Query
healthStore.stop(self.currentQuery!)
session = nil
default:
print("Unexpected state: \(toState)")
}
}
func workoutSession(_ workoutSession: HKWorkoutSession, didFailWithError error: Error) {
//Do Nothing
}
func startWorkout(){
// If a workout has already been started, do nothing.
if (session != nil) {
return
}
// Configure the workout session.
let workoutConfiguration = HKWorkoutConfiguration()
workoutConfiguration.activityType = .running
workoutConfiguration.locationType = .outdoor
do {
session = try HKWorkoutSession(configuration: workoutConfiguration)
session?.delegate = self
} catch {
fatalError("Unable to create workout session")
}
healthStore.start(self.session!)
print("Start Workout Session")
}
func heartRateQuery(_ startDate: Date) -> HKQuery? {
let quantityType = HKObjectType.quantityType(forIdentifier: HKQuantityTypeIdentifier.heartRate)
let datePredicate = HKQuery.predicateForSamples(withStart: startDate, end: nil, options: .strictEndDate)
let predicate = NSCompoundPredicate(andPredicateWithSubpredicates:[datePredicate])
let heartRateQuery = HKAnchoredObjectQuery(type: quantityType!, predicate: predicate, anchor: nil, limit: Int(HKObjectQueryNoLimit)) { (query, sampleObjects, deletedObjects, newAnchor, error) -> Void in
//Do nothing
}
heartRateQuery.updateHandler = {(query, samples, deleteObjects, newAnchor, error) -> Void in
guard let samples = samples as? [HKQuantitySample] else {return}
DispatchQueue.main.async {
guard let sample = samples.first else { return }
let value = sample.quantity.doubleValue(for: HKUnit(from: "count/min"))
print("This line is executed!")
self.label.setText(String(UInt16(value))) //Update label
}
}
return heartRateQuery
}
}
import UIKit
import HealthKit
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
return true
}
func applicationWillResignActive(_ application: UIApplication) {
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
// Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
}
func applicationDidEnterBackground(_ application: UIApplication) {
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
}
func applicationWillEnterForeground(_ application: UIApplication) {
// Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
}
func applicationDidBecomeActive(_ application: UIApplication) {
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
}
func applicationWillTerminate(_ application: UIApplication) {
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
}
let healthStore = HKHealthStore()
func applicationShouldRequestHealthAuthorization(_ application: UIApplication) {
healthStore.handleAuthorizationForExtension{
(success,error) in
}
}
}

Related

Swift SFSafariViewController present show blank page

EDIT2
here is a MWC containing 2 classes with only the SFSafariViewController for opening an url embedded. What I get on screen is a blank page
The files are also here https://github.com/camillegallet/testSwiftSafariEmbeded
AppDelegate
import UIKit
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
return true
}
func applicationWillResignActive(_ application: UIApplication) {
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
// Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
}
func applicationDidEnterBackground(_ application: UIApplication) {
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
}
func applicationWillEnterForeground(_ application: UIApplication) {
// Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
}
func applicationDidBecomeActive(_ application: UIApplication) {
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
}
func applicationWillTerminate(_ application: UIApplication) {
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
}
}
View controller
import UIKit
import WebKit
import SafariServices
class ViewController: UIViewController {
#IBOutlet weak var KronosWebsite: WKWebView!
override func loadView() {
KronosWebsite = WKWebView()
self.view = KronosWebsite
}
override func viewDidLoad() {
super.viewDidLoad()
openGoogle()
}
func openGoogle(){
let url2=URL(string: "http://www.google.com")
let web = SFSafariViewController(url: url2!)
let keyWindow = UIApplication.shared.windows.filter {$0.isKeyWindow}.first
if var topController = keyWindow?.rootViewController {
while let presentedViewController = topController.presentedViewController {
topController = presentedViewController
}
do{
topController.present(web, animated: true, completion: nil)
}catch let error {
DispatchQueue.main.async {
print("ERROR \(error)")
}
}
}
}
}
I've this old function in a library
public func authorizeSafariEmbedded(from controller: UIViewController, at url: URL) throws -> SFSafariViewController {
safariViewDelegate = OAuth2SFViewControllerDelegate(authorizer: self)
let web = SFSafariViewController(url: url)
web.title = oauth2.authConfig.ui.title
web.delegate = safariViewDelegate as! OAuth2SFViewControllerDelegate
if #available(iOS 10.0, *), let barTint = oauth2.authConfig.ui.barTintColor {
web.preferredBarTintColor = barTint
}
if #available(iOS 10.0, *), let tint = oauth2.authConfig.ui.controlTintColor {
web.preferredControlTintColor = tint
}
web.modalPresentationStyle = oauth2.authConfig.ui.modalPresentationStyle
willPresent(viewController: web, in: nil)
controller.present(web, animated: true, completion: nil)
return web
}
I call this function with those lines
let keyWindow = UIApplication.shared.windows.filter {$0.isKeyWindow}.first
if var topController = keyWindow?.rootViewController {
while let presentedViewController = topController.presentedViewController {
topController = presentedViewController
}
do{
let web = try authorizer.authorizeSafariEmbedded(from: topController,at: url!)
}catch let error {
DispatchQueue.main.async {
print("ERROR \(error)")
}
}
}
But I keep having a blank page, I've not found a correct working solution on the web
I've also tested with
let url=URL(string: "http://www.google.com")
even this don't works
public func authorizeSafariEmbedded(from controller: UIViewController, at url: URL) throws -> SFSafariViewController {
let web = SFSafariViewController(url: url)
web.title = oauth2.authConfig.ui.title
controller.present(web, animated: true, completion: nil)
return web
}
Thanks in advance
Here what I've done to make it works
import UIKit
import WebKit
import SafariServices
class ViewController: UIViewController {
var safariVC = SFSafariViewController(url: URL(string: "https://apple.com")!)
#IBOutlet weak var KronosWebsite: WKWebView!
override func loadView() {
KronosWebsite = WKWebView()
self.view = KronosWebsite
}
func addViewControllerAsChildViewController() {
addChild(safariVC)
self.view.addSubview(safariVC.view)
safariVC.didMove(toParent: self)
self.setUpConstraints()
}
override func viewDidLoad() {
super.viewDidLoad()
addViewControllerAsChildViewController()
}
func setUpConstraints() {
self.safariVC.view.translatesAutoresizingMaskIntoConstraints = false
self.safariVC.view.topAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.topAnchor, constant: 30).isActive = true
self.safariVC.view.bottomAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.bottomAnchor, constant: -30).isActive = true
self.safariVC.view.leadingAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.leadingAnchor, constant: 30).isActive = true
self.safariVC.view.trailingAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.trailingAnchor, constant: -30).isActive = true
}
}

How do I fix the error: "Thread 1: EXC_BAD_ACCESS (code=2, address=0x7ffee0761ed8)"

I am using swift to build an app in Xcode. it builds fine, but when it runs, it stops and gives me an error on the line a declare my delegate(this line: "weak var delegate: LocationActions?") in LocationService.swift. Here is the error:
Thread 1: EXC_BAD_ACCESS (code=2, address=0x7ffee0761ed8)
I tried plenty of things but couldn't figure it out. can anyone help me solve this problem? If you can, thank you so much here is my code:
LocationService.swift
import CoreData
import Moya
import CoreLocation
import Alamofire
protocol LocationActions: class {
func didChangeLocationAuthorizationRD()
}
class LocationService:NSObject, ObservableObject, CLLocationManagerDelegate {
weak var delegate: LocationActions?
var newLocation: ((Result<CLLocation>) -> Void)?
let locationManager: CLLocationManager
lazy var latitude = Double(locationManager.location?.coordinate.latitude ?? 100000.00)
lazy var longitude = Double(locationManager.location?.coordinate.longitude ?? 100000.00)
lazy var tempLatitude = Double(locationManager.location?.coordinate.latitude ?? 100000.00)
let jsonDecoder = JSONDecoder()
var lat = 0.0
var long = 0.0
let dataSource = DataSource()
func requestLocationAuthorization() {
locationManager.requestWhenInUseAuthorization()
}
func getLocation() {
locationManager.requestLocation()
}
var didChangeStatus: ((Bool) -> Void)?
func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
switch status {
case .notDetermined, .restricted, .denied:
didChangeStatus?(false)
case .authorizedAlways, .authorizedWhenInUse:
didChangeStatus?(true)
self.delegate?.didChangeLocationAuthorizationRD()
}
}
override init() {
self.locationManager = CLLocationManager()
super.init()
self.locationManager.delegate = self
}
func setup(latOrLong : String) -> Double {
self.locationManager.requestWhenInUseAuthorization()
if CLLocationManager.headingAvailable() {
self.locationManager.startUpdatingLocation()
}
if latOrLong == "lat" {
return self.latitude
}else if latOrLong == "long" {
return self.longitude
} else {
print("error enter either lat or long in the paramaters for the function setup located in LocationServices.swift")
return 3.141592653
}
}
}
AppDelegate.swift
import UIKit
import CoreData
import Moya
import Alamofire
import AlamofireImage
import Foundation
import CoreLocation
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate, CLLocationManagerDelegate {
var theViewModels = [RestrauntListViewModel]()
let locationService = LocationService()
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
let locationServices = LocationService()
let lat = locationServices.setup(latOrLong: "lat")
let long = locationServices.setup(latOrLong: "long")
locationServices.lat = lat
locationServices.long = long
let dataSource = DataSource()
loadBusinesses(lat: lat, long: long)
print("this is the view models in appDelegate: \(theViewModels)")
locationService.didChangeStatus = { [weak self] success in
if success {
self?.locationService.getLocation()
}
}
locationService.newLocation = { [weak self] result in
switch result {
case .success(let location):
self?.loadBusinesses(lat: location.coordinate.latitude, long: location.coordinate.longitude)
case .failure(let error):
assertionFailure("Error getting the users location \(error)")
}
}
locationService.delegate = self
return true
}
func loadBusinesses (lat: Double, long: Double) {
var contentView = ContentView()
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")
contentView.tapToDecideText = "Please allow us to use your location in settings so that we can show you restraunts near by. Once you have let us use your location please restart the application."
case .authorizedAlways, .authorizedWhenInUse:
print("Access")
service.request(.search(lat: lat, long: long)) { (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)")
}
}
}
}
extension AppDelegate: LocationActions{
func didChangeLocationAuthorizationRD() {
locationService.requestLocationAuthorization()
}
}
You hide member variable with local one which later released
let locationService = LocationService() // 1st
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
let locationServices = LocationService() // 2nd <<< remove this line
This means you are accessing something that is not the exact type of component. So double-check your all variables and classes some variables might be the wrong Inheritance.
Example:
You are working with a CustomImageView but in your reference variable its extends UIImageVIew

present a specific VC when local notification is tapped Swift

I tried to follow various solutions to the same problem in other posts but none seems to be applicable to my code.
I merged an alarm into my app and my goal is to get to NewMapViewControlleron user tapping on alarm local notification and call checkAlerts2() function which is not normally called when going to that VC via the app menu.
Thank you for you help as usual.
This is my AppDelegate:
import UIKit
import CoreData
import Foundation
import AudioToolbox
import AVFoundation
import Firebase
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate,AVAudioPlayerDelegate, AlarmApplicationDelegate {
var window: UIWindow?
var audioPlayer: AVAudioPlayer?
let alarmScheduler: AlarmSchedulerDelegate = Scheduler()
var alarmModel: Alarms = Alarms()
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
var error: NSError?
do {
try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback)
} catch let error1 as NSError{
error = error1
print("could not set session. err:\(error!.localizedDescription)")
}
do {
try AVAudioSession.sharedInstance().setActive(true)
} catch let error1 as NSError{
error = error1
print("could not active session. err:\(error!.localizedDescription)")
}
window?.tintColor = UIColor.blue
FirebaseApp.configure()
return true
}
//receive local notification when app in foreground
func application(_ application: UIApplication, didReceive notification: UILocalNotification) {
//show an alert window
let storageController = UIAlertController(title: "Check route for alerts?", message: nil, preferredStyle: .alert)
var isSnooze: Bool = false
var soundName: String = ""
var routeName: String = ""
var index: Int = -1
if let userInfo = notification.userInfo {
isSnooze = userInfo["snooze"] as! Bool
soundName = userInfo["soundName"] as! String
routeName = userInfo["routeName"] as! String
index = userInfo["index"] as! Int
}
playSound(soundName)
//schedule notification for snooze
if isSnooze {
let snoozeOption = UIAlertAction(title: "Snooze", style: .default) {
(action:UIAlertAction)->Void in self.audioPlayer?.stop()
self.alarmScheduler.setNotificationForSnooze(snoozeMinute: 9, soundName: soundName, routeName: routeName, index: index)
}
storageController.addAction(snoozeOption)
}
let stopOption = UIAlertAction(title: "OK", style: .default) {
(action:UIAlertAction)->Void in self.audioPlayer?.stop()
AudioServicesRemoveSystemSoundCompletion(kSystemSoundID_Vibrate)
self.alarmModel = Alarms()
self.alarmModel.alarms[index].onSnooze = false
//change UI
var mainVC = self.window?.visibleViewController as? MainAlarmViewController
// var mainVC = self.window?.visibleViewController as? NewMapViewController
if mainVC == nil {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
mainVC = storyboard.instantiateViewController(withIdentifier: "Alarm") as? MainAlarmViewController
// mainVC = storyboard.instantiateViewController(withIdentifier: "Alarm") as? NewMapViewController
}
mainVC!.changeSwitchButtonState(index: index)
// MainAlarmViewController?.changeSwitchButtonState(index: index)
}
storageController.addAction(stopOption)
window?.visibleViewController?.navigationController?.present(storageController, animated: true, completion: nil)
}
//snooze notification handler when app in background
func application(_ application: UIApplication, handleActionWithIdentifier identifier: String?, for notification: UILocalNotification, completionHandler: #escaping () -> Void) {
var index: Int = -1
var soundName: String = ""
var routeName: String = ""
if let userInfo = notification.userInfo {
soundName = userInfo["soundName"] as! String
routeName = userInfo["routeName"] as!String
index = userInfo["index"] as! Int
}
self.alarmModel = Alarms()
self.alarmModel.alarms[index].onSnooze = false
if identifier == Id.snoozeIdentifier {
alarmScheduler.setNotificationForSnooze(snoozeMinute: 9, soundName: soundName, routeName: routeName, index: index)
self.alarmModel.alarms[index].onSnooze = true
}
completionHandler()
}
//AlarmApplicationDelegate protocol
func playSound(_ soundName: String) {
//vibrate phone first
AudioServicesPlaySystemSound(SystemSoundID(kSystemSoundID_Vibrate))
//set vibrate callback
AudioServicesAddSystemSoundCompletion(SystemSoundID(kSystemSoundID_Vibrate),nil,
nil,
{ (_:SystemSoundID, _:UnsafeMutableRawPointer?) -> Void in
AudioServicesPlaySystemSound(SystemSoundID(kSystemSoundID_Vibrate))
},
nil)
let url = URL(fileURLWithPath: Bundle.main.path(forResource: soundName, ofType: "mp3")!)
var error: NSError?
do {
audioPlayer = try AVAudioPlayer(contentsOf: url)
} catch let error1 as NSError {
error = error1
audioPlayer = nil
}
if let err = error {
print("audioPlayer error \(err.localizedDescription)")
return
} else {
audioPlayer!.delegate = self
audioPlayer!.prepareToPlay()
}
//negative number means loop infinity
audioPlayer!.numberOfLoops = -1
audioPlayer!.play()
}
//AVAudioPlayerDelegate protocol
func audioPlayerDidFinishPlaying(_ player: AVAudioPlayer, successfully flag: Bool) {
}
func audioPlayerDecodeErrorDidOccur(_ player: AVAudioPlayer, error: Error?) {
}
func applicationWillResignActive(_ application: UIApplication) {
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
// Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
}
func applicationDidEnterBackground(_ application: UIApplication) {
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
}
func applicationWillEnterForeground(_ application: UIApplication) {
// Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
}
func applicationDidBecomeActive(_ application: UIApplication) {
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
// audioPlayer?.play()
alarmScheduler.checkNotification()
}
func applicationWillTerminate(_ application: UIApplication) {
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
}
// 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: "fix-it mapView")
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)")
}
}
}
}

Swift: "mapView.showUserLocation = true" returns "fatal error: unexpectedly found nil while unwrapping an Optional value (lldb) "

So I'm trying to search for local businesses in Swift using keywords like "bar", or "pizza". I linked the search to a button action so that the locations will pop up on the map within a defined region. However, I can't even get the application to load with user location because I get a nil error.
Here's my AppDelegate:
import UIKit
import CoreLocation
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
var locationManager: CLLocationManager?
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
// Override point for customization after application launch.
locationManager = CLLocationManager()
locationManager?.requestWhenInUseAuthorization()
return true
}
func applicationWillResignActive(application: UIApplication) {
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
// Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
}
func applicationDidEnterBackground(application: UIApplication) {
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
}
func applicationWillEnterForeground(application: UIApplication) {
// Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
}
func applicationDidBecomeActive(application: UIApplication) {
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
}
func applicationWillTerminate(application: UIApplication) {
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
}
}
And here's my ViewController.swift:
import Foundation
import UIKit
import MapKit
class ViewController: UIViewController, MKMapViewDelegate {
#IBOutlet weak var mapView: MKMapView!
#IBAction func searchBars(sender: AnyObject) {
let request = MKLocalSearchRequest()
request.naturalLanguageQuery = "Bar"
request.region = mapView.region
let search = MKLocalSearch(request: request)
search.startWithCompletionHandler({(response: MKLocalSearchResponse!, error: NSError!) in
if error != nil {
println("Error occurred in search: \(error.localizedDescription)")
} else if response.mapItems.count == 0 {
println("No matches found")
for item in response.mapItems as [MKMapItem] {
println("Name = \(item.name)")
println("Phone = \(item.phoneNumber)")
}
}
})
}
func mapView(mapView: MKMapView!, didUpdateUserLocation userLocation: MKUserLocation!) {
mapView.centerCoordinate = userLocation.location.coordinate
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
mapView.showsUserLocation = true
mapView.delegate = self
}
#IBAction func zoomIn(sender: AnyObject) {
let userLocation = mapView.userLocation
let region = MKCoordinateRegionMakeWithDistance(userLocation.location.coordinate, 2000, 2000)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
The line that returns the nil error is in my ViewController.swift file under #IBAction func zoomIn with the line: let region = MKCoordinateRegionMakeWithDistance(userLocation.location.coordinate, 2000, 2000). Which gives a nil value for some reason.
What you're doing with this line is creating a mapView object which is not instantiated yet.
weak var mapView: MKMapView!
You get the error because you are trying to change showsUserLocation property to an object which doesn't exist yet, it's nil.
What you need to do, if you created the map in a storyboard, is to remove the weak var line and put a IBOutlet instead (Ctrl + Click and drag from the storyboard).
Many thanks to Skoua for his help. I figured out what was wrong on my own after he helped me with the IBOutlet.
Here's the corrected code.
#IBAction func searchBars(sender: AnyObject) {
matchingItems.removeAll()
let request = MKLocalSearchRequest()
request.naturalLanguageQuery = "bar"
request.region = mapView.region
let search = MKLocalSearch(request: request)
search.startWithCompletionHandler({(response: MKLocalSearchResponse!, error: NSError!) in
if error != nil {
println("Error occurred in search: \(error.localizedDescription)")
} else if response.mapItems.count == 0 {
println("No matches found")
//This is where the problem occured
} else {
println("Matches found")
//I needed to insert an else statement for matches being found
for item in response.mapItems as [MKMapItem] {
//This prints the 'matches' into [MKMapItem]
println("Name = \(item.name)")
println("Phone = \(item.phoneNumber)")
self.matchingItems.append(item as MKMapItem)
println("Matching items = \(self.matchingItems.count)")
var annotation = MKPointAnnotation()
annotation.coordinate = item.placemark.coordinate
annotation.title = item.name
self.mapView.addAnnotation(annotation)
}
}
})
}

Getting CLBeacon's information from AppDelegate to View Controller in Swift

I'm new to swift and have gone around and around trying to figure it out. I know I have it over complicated if I had to guess but need some help.
I'm trying to use iBeacon to read the UUID, Major and Minor values off of a beacon then use that to drive an image in the view controller.
In the AppDelegate.swift file I am able to get the information and use println to get it out. The AppDelegate file is the following:
import UIKit
import CoreLocation
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
var locationManager: CLLocationManager?
var lastProximity: CLProximity?
var lastUUID: NSUUID!
var lastBeacanIdentifier:String = ""
var lastMajorValue: NSNumber = 0.0
var lastMinorValue: NSNumber = 0.0
func application(application: UIApplication,
didFinishLaunchingWithOptions launchOptions: NSDictionary?) -> Bool {
let uuidString = "99C2E498-7606-4575-A353-5F710834E75B"
let beaconIdentifier = "co.Company"
let beaconUUID:NSUUID = NSUUID(UUIDString: uuidString)
let beaconRegion:CLBeaconRegion = CLBeaconRegion(proximityUUID: beaconUUID, identifier: beaconIdentifier)
locationManager = CLLocationManager()
if(locationManager!.respondsToSelector("requestAlwaysAuthorization")) {
locationManager!.requestAlwaysAuthorization()
}
locationManager!.delegate = self
locationManager!.pausesLocationUpdatesAutomatically = false
locationManager!.startMonitoringForRegion(beaconRegion)
locationManager!.startRangingBeaconsInRegion(beaconRegion)
locationManager!.startUpdatingLocation()
if(application.respondsToSelector("registerUserNotificationSettings:")) {
application.registerUserNotificationSettings(
UIUserNotificationSettings(
forTypes: UIUserNotificationType.Alert | UIUserNotificationType.Sound,
categories: nil
)
)
}
return true
}
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
// Override point for customization after application launch.
return true
}
func applicationWillResignActive(application: UIApplication) {
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
// Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
}
func applicationDidEnterBackground(application: UIApplication) {
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
}
func applicationWillEnterForeground(application: UIApplication) {
// Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
}
func applicationDidBecomeActive(application: UIApplication) {
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
}
func applicationWillTerminate(application: UIApplication) {
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
}
}
extension AppDelegate: CLLocationManagerDelegate {
func sendLocalNotificationWithMessage(message: String!) {
let notification:UILocalNotification = UILocalNotification()
notification.alertBody = message
UIApplication.sharedApplication().scheduleLocalNotification(notification)
}
func locationManager(manager: CLLocationManager!,
didRangeBeacons beacons: [AnyObject]!,
inRegion region: CLBeaconRegion!) {
NSLog("didRangeBeacons");
var message:String = ""
if(beacons.count > 0) {
let nearestBeacon:CLBeacon = beacons[0] as CLBeacon
if(nearestBeacon.proximity == lastProximity ||
nearestBeacon.proximity == CLProximity.Unknown) {
return;
}
lastProximity = nearestBeacon.proximity;
lastMajorValue = nearestBeacon.major;
lastMinorValue = nearestBeacon.minor;
lastUUID = nearestBeacon.proximityUUID;
switch nearestBeacon.proximity {
case CLProximity.Far:
message = "You are far away from the beacon";
println(lastMajorValue)
println(lastMinorValue)
println(lastUUID)
case CLProximity.Near:
message = "You are near the beacon";
println(lastMajorValue)
println(lastMinorValue)
println(lastUUID)
case CLProximity.Immediate:
message = "You are in the immediate proximity of the beacon";
println(lastMajorValue)
println(lastMinorValue)
println(lastUUID)
case CLProximity.Unknown:
return
}
} else {
message = "No beacons are nearby"
}
NSLog("%#", message)
sendLocalNotificationWithMessage(message)
}
func locationManager(manager: CLLocationManager!,
didEnterRegion region: CLRegion!) {
manager.startRangingBeaconsInRegion(region as CLBeaconRegion)
manager.startUpdatingLocation()
NSLog("You entered the region")
sendLocalNotificationWithMessage("You entered the region")
}
func locationManager(manager: CLLocationManager!,
didExitRegion region: CLRegion!) {
manager.stopRangingBeaconsInRegion(region as CLBeaconRegion)
manager.stopUpdatingLocation()
NSLog("You exited the region")
sendLocalNotificationWithMessage("You exited the region")
}
}
The View Controller file is the following:
import Foundation
import UIKit
import CoreLocation
class ViewController: UIViewController{
#IBOutlet weak var advertismentImageArea: UIImageView!
#IBAction func closeAdvertisementButton(sender: UIButton) {
advertismentImageArea.hidden = true
}
var beaconInformation: AppDelegate!
override func viewDidLoad() {
super.viewDidLoad()
var closestBeacon = beaconInformation
var majorNumber = closestBeacon.lastMajorValue
if majorNumber == 6303 {
advertismentImageArea.image = UIImage(named: "AdOne")
} else if majorNumber == 21456 {
advertismentImageArea.image = UIImage(named: "AdTwo")
} else {
return advertismentImageArea.hidden = true;
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
I would really appreciate any help you all can provide.
One possible solution would be to use the iOS Delegation pattern. It's not the only way to solve this problem.
What you would do would be to create a Protocol in your AppDelegate class
#protocol BeaconLocationDelegate
{
func majorBeaconChanged(majorValue:NSNumber)
}
You would then also add the following variable to your AppDelegate class
weak var locationDelegate: BeaconLocationDelegate?
Inside your ViewController class you would then declare that your class implements the BeaconLocationDelegate protocol
class ViewController: UIViewController, BeaconLocationDelegate
and then somewhere in viewDidload add the following line of code
UIApplication.sharedApplication().delegate?.locationDelegate = self
and then implement the protocol method to update the UI however you want for your app
func majorBeaconChanged(majorValue:NSNumber)
And lastly, inside your AppDelegate class whenever you detect the change in the beacon you would then invoke code like:
locationDelegate?.majorBeaconChanged(newMajorValue)

Resources