Write HeartRate on HealthKit - apple-watch

I have a problem to send the heart rate data to healthkit.
I want to read (in apple watch display) and write the heart rate data for my apple watch app.
i don't have any problem to read, but i can't send data.
func updateHeartRate(samples: [HKSample]?) {
guard let heartRateSamples = samples as? [HKQuantitySample] else {return}
dispatch_async(dispatch_get_main_queue()) {
guard let sample = heartRateSamples.first else{return}
let value2 = sample.quantity.doubleValueForUnit(self.heartRateUnit)
self.label.setText(String(UInt16(value2)))
let now = NSDate()
print(value2)
print(now)
self.animateHeart()
let completion: ((Bool, NSError?) -> Void) = {
(success, error) -> Void in
if( error != nil ) {
print("Error saving HR")
} else {
print("HR saved successfully!")
}
}
self.healthStore.saveObject(sample, withCompletion: completion)
In display: print("HR saved successfully")
Can someone help me?
Thanks

Related

How to detect if there is no more post to fetch in CollectionView?

I am making new app with Xcode using Swift and i am fetching posts from my WordPress website , all works fine but there is one problem, when i scroll down to the very last post of category then the indicator is just running and nothing happens, i want when there is no more post then Progress bar should stop running and i want to toast a message that there is no more post , how is that possible ? this is my code to fetch posts
func fetchPostData(completionHandler: #escaping ([Postimage]) -> Void ) {
let url = URL(string: "https://www.sikhnama.com/wp-json/wp/v2/posts/?categories=4&page=\(page)\(sortBy)")!
print(url)
let task = URLSession.shared.dataTask(with: url) { (data, response, error) in
guard let data = data else {return}
do {
let postsData = try JSONDecoder().decode([Postimage].self, from: data)
completionHandler(postsData)
DispatchQueue.main.async {
if(self.newsData.isEmpty == false){
print("collection view empty")
self.collectionView.reloadData()
SVProgressHUD.dismiss()
}
else{
if(self.collectionView == nil){
print("collection view nill")
self.fetchPostData { (posts) in
self.newsData = posts }
}
}
}
}
catch {
let error = error
print(String(describing: error))
}
}
task.resume()
}
can you please help ?

How can I make multiple uploads to Firebase Storage asynchronous?

I've got an array of data which I want uploading to Firebase Storage in order, so the download urls which are retrieved are in order too.
I've tried to use DispatchGroup and DispatchSemaphore for this, but I'm guessing I've inserted them in incorrect positions in my code, because my print statement which prints the index and the urlString aren't printed in order. How can I fix this?
import Foundation
import FirebaseStorage
func uploadToStorage(dataArray: [Data],
completion: #escaping (_ success: Bool, _ urlsAsStringArray: [String]) -> Void) {
let dispatchGroup = DispatchGroup()
let dispatchSemaphore = DispatchSemaphore(value: 0)
let dispatchQueue = DispatchQueue(label: "someTask")
var urlsAsStringArray: [String] = []
dispatchQueue.async {
for (index, data) in dataArray.enumerated() {
dispatchGroup.enter()
dispatchSemaphore.signal()
let imageId = NSUUID().uuidString
let fileName = "\(imageId).jpg"
let folder = Storage.storage().reference()
.child("photos")
folder.child(fileName).putData(data, metadata: nil) { (metadata, error) in
if let error = error {
print("\n \nError with Firebase Storage photo upload:")
print(error)
dispatchGroup.leave()
dispatchSemaphore.wait()
completion(false, [])
} else {
print("\n \nSuccess with Firebase Storage photo upload")
folder.child(fileName).downloadURL { (url, error) in
if let error = error {
print("\n \nError with retrieving Firebase Storage photo download URL:")
print(error)
dispatchGroup.leave()
dispatchSemaphore.wait()
completion(false, [])
} else {
if let urlAsString = url?.absoluteString {
print("\n \nSuccess with retrieving Firebase Storage photo download URL")
print("\n \nPhoto message to be sent to Firebase Firestore has URL link: \(urlAsString)")
urlsAsStringArray.append(urlAsString)
print("Index is: \(index). Photo uploaded has url: \(urlAsString)")
dispatchGroup.leave()
dispatchSemaphore.wait()
if index == dataArray.count - 1 {
completion(true, urlsAsStringArray)
}
}
}
}
}
}
}
}
}

Live heart rate record time interval - WatchOS

I have created a watch app with live heart rate record, for that i have used the workout session and HKAnchoredObjectQuery to fetch the results. In this apple has mentioned that, every 5 seconds will update the heart rate value, but in my case it will take upto 5-10 sec to update. I am using watch serious 3 and i need to collect the value for exactly every 5 seconds.
func startWorkout() {
if (session != nil) {
return
}
let workoutConfiguration = HKWorkoutConfiguration()
workoutConfiguration.activityType = .walking
workoutConfiguration.locationType = .outdoor
do {
session = try HKWorkoutSession(healthStore: healthStore, configuration: workoutConfiguration)
session?.delegate = self
} catch {
print("Unable to create the workout session!")
}
session?.startActivity(with: Date())
}
func startHeartRateStreamingQuery(_ workoutStartDate: Date){
guard let quantityType = HKObjectType.quantityType(forIdentifier: HKQuantityTypeIdentifier.heartRate) else { return nil }
let datePredicate = HKQuery.predicateForSamples(withStart: workoutStartDate, 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
self.updateHeartRate(sampleObjects)
}
heartRateQuery.updateHandler = {(query, samples, deleteObjects, newAnchor, error) -> Void in
self.updateHeartRate(samples)
}
healthStore.execute(heartRateQuery)
}
func updateHeartRate(_ samples: [HKSample]?) {
guard let heartRateSamples = samples as? [HKQuantitySample] else {return}
for sample in heartRateSamples {
let timeStamp = sample.startDate
let value = sample.quantity
print("\(timeStamp)_\(value)")
}
}

Swift / Firebase: Cancel downloading an image?

I have the following basic code implemented to download an image from Firebase. The function is called from within a UICollectionViewCell. There are cases when a user might scroll quickly past the cell and in those cases, I would like to cancel the .getData download task if it has not yet returned. Is there a way to cancel .getData?
private func downloadImage(path: StorageReference, handler: #escaping (_ image: UIImage?) -> ()) {
if let cachedImage = imageCache.object(forKey: path) {
handler(cachedImage)
} else {
path.getData(maxSize: 27 * 1024 * 1024) { (data, error) in
if let data = data, let image = UIImage(data: data) {
handler(image)
imageCache.setObject(image, forKey: path)
} else {
handler(nil)
guard let error = error else { return }
print(error)
}
}
}
}
If you capture your Firebase Storage operations as properties, you can call methods on them to pause, resume, or cancel them. For example:
let download = path.getData(maxSize: 27 * 1024 * 1024) { (data, error) in
if let data = data, let image = UIImage(data: data) {
handler(image)
imageCache.setObject(image, forKey: path)
} else {
handler(nil)
guard let error = error else { return }
print(error)
}
}
download.pause()
download.resume()
download.cancel()
https://firebase.google.com/docs/storage/ios/download-files?authuser=0#manage_downloads

How to prevent an app crash or freeze due to a slow connection when retrieving a remote photo in Swift?

I want to display avatar image in my table view cell by the url string. and it will crash when the phone is not connect to the internet, so I added Reachability swift to it. but now I face another problem, when the user leaving the wifi zone or the internet connection is not stable, the app will freeze, I'm not able to tap anything until I walk back the strong wifi zone. why?
let imageData:NSData = try! NSData(contentsOf: imageUrl)
this code will crash so I try add do & catch but still not working. is it because the app can't connect to the url string and get the data so that the app will be freeze? how to prevent an app crash or freeze due to a slow connection when retrieving a remote photo?
if Reachability.shared.isConnectedToNetwork(){
if let crew = user!["crew"] as? [String:Any], let crewAva = crew["crew_avatar"] as? String {
let imageUrlString = crewAva
let imageUrl:URL = URL(string: imageUrlString)!
DispatchQueue.main.async(execute: {
do{
let imageData:NSData = try NSData(contentsOf: imageUrl)
let image = UIImage(data: imageData as Data)
self.avaImg.image = image
}
catch{
print("error")
}
})
}
}else{
print("Not reachable")
}
From the NSData documentation:
init?(contentsOf url: URL)
Important
Don't use this synchronous method to request network-based URLs. For network-based URLs, this method can block the current thread for tens of seconds on a slow network, resulting in a poor user experience, and in iOS, may cause your app to be terminated.
Instead, for non-file URLs, consider using the dataTask(with:completionHandler:) method of the NSURLSession class. See URL Session Programming Guide for details.
Solution
func getDataFromUrl(url: URL, completion: #escaping (Data?, URLResponse?, Error?) -> ()) {
URLSession.shared.dataTask(with: url) { data, response, error in
completion(data, response, error)
}.resume()
}
func downloadImage(url: URL) {
getDataFromUrl(url: url) { data, response, error in
guard let data = data, error == nil else { return }
print(response?.suggestedFilename ?? url.lastPathComponent)
DispatchQueue.main.async() {
self.avaImg.image = UIImage(data: data)
}
}
}
override func viewWillAppear(_ animated: Bool) {
if let crew = user!["crew"] as? [String:Any], let crewAva = crew["crew_avatar"] as? String {
let imageUrlString = crewAva
let url = URL(string: imageUrlString)!
downloadImage(url: url)
}
}
Try only updating the UI on the main thread.
if Reachability.shared.isConnectedToNetwork(){
if let crew = user!["crew"] as? [String:Any], let crewAva = crew["crew_avatar"] as? String {
let imageUrlString = crewAva
let imageUrl:URL = URL(string: imageUrlString)!
let imageData:NSData = try NSData(contentsOf: imageUrl)
let image = UIImage(data: imageData as Data)
DispatchQueue.main.async(execute: {
do{
self.avaImg.image = image
}
catch{
print("error")
}
})
}
}else{
print("Not reachable")
}