Call external function using WatchKit force touch MenuItem
The fatal error is (or was) caused by this line:
let wSM = WorkoutSessionManager()
That line creates a new instance of WorkoutSessionManager and calls init()
on it.
Swift provides a default initializer called init()
for any structure or class that provides default values for all of its properties and does not provide at least one initializer itself. But WorkoutSessionManager does not provide default values for the healthStore
and workoutSession
properties (and those properties are not optionals), and it provides its own initializer named init(context:)
, so it has no default initializer.
You need to either create your instance of WorkoutSessionManager using the designated initializer init(context:)
(passing an appropriate instance of WorkoutSessionContext) or provide a default initializer for WorkoutSessionManager named init()
.
The precise manner in which you should do the former depends on the implementation of the rest of your app and the presentation of your DashboardController. I assume you are trying to recreate the "Fit" app shown in WWDC 2015 Session 203.
In that demonstration, the initial controller is an instance of ActivityInterfaceController, and that controller is responsible for presenting the next interface (via segues created in the storyboard). You can see the following code in the ActivityInterfaceController class:
override func contextForSegueWithIdentifier(segueIdentifier: String) -> AnyObject? {
let activityType: HKWorkoutActivityType
switch segueIdentifier {
case "Running":
activityType = .Running
case "Walking":
activityType = .Walking
case "Cycling":
activityType = .Cycling
default:
activityType = .Other
}
return WorkoutSessionContext(healthStore: self.healthStore, activityType: activityType)
}
The function above creates and returns a new instance of WorkoutSessionContext using an instance of HKHealthStore held by the initial controller. The context returned by that function is passed to the destination interface controller for the relevant segue through awakeWithContext
.
For transitions in code, you can pass a context instance using equivalent functions such as pushControllerWithName(context:)
which also lead to awakeWithContext
.
If your initial controller is similar to the above, you can access the passed context in awakeWithContext
in your DashboardController class and use it to configure a new instance of WorkoutSessionManager:
class DashboardController: WKInterfaceController
{
// ...
var wSM: WorkoutSessionManager?
override func awakeWithContext(context: AnyObject?) {
super.awakeWithContext(context)
if context is WorkoutSessionContext {
wSM = WorkoutSessionManager(context: context as! WorkoutSessionContext)
}
addMenuItemWithItemIcon(.Accept, title: "Save", action: #selector(DashboardController.saveSession))
}
// ...
}
Creating an instance of WorkoutSessionManager in that way avoids calling the (non-existent) init()
initializer and permits reuse of the HKHealthStore instance. Whether that approach is open to you depends on the rest of your code and the way you are presenting your DashboardController.
Note that you should avoid creating multiple instances of WorkoutSessionManager. Use a singleton to provide a single instance of WorkoutSessionManager that is shared across your extension.
Use menu item for open another interface controller
Yes, it is possible. You need to create an IBAction
for your Menu Item and call the desired navigation function inside that IBAction
. I will show you code for using presentController
, but you can use any other available navigation function from WatchKit
.
@IBAction func presentOtherInterfaceController() {
self.presentController(withName: "MyOtherInterfaceController", context: nil)
}
Selector not called on selecting menu item after force touch
Solved.
Though its the result of a silly mistake (aren't most problems?), I think this is something a lot of people will run into, so I'll keep it here with my answer.
I enabled force touch on the simulator, so I could show the menu. When I'm tapping again on the button, force touch is still enabled, so I'm force touching, thus dismissing the menu.
Solution: Disable force touch before tapping a menu button.
WatchKit menu item not showing on real device
This is usually because the app can't find the custom image for your button. Is your image included in the WatchKit App bundle? Unfortunately, Interface Builder allows you to use an image from any bundle, but it won't work on a real device.
Any way to disable the force touch detection for my Apple WatchKit 2 app
Unfortunately there is no way to disable the force touch attempt at this time. Even Apple's own watch apps that don't have menus still show the force touch "bouce" effect if there is no menu items.
Is it possible to query live HKUnit data directly from another class without passing data?
If I understand correctly, you want to query the HealthKit store for certain kinds of samples, and update your UI every time new samples are saved to the store.
You can do this in several ways, including by using delegation, closures, or notifications. See below for sample code using delegation.
You've already defined a WorkoutSessionManagerDelegate protocol in your WorkoutSessionManager class (shown here). If that protocol is the same as that used in WWDC 2015 Session 203, it provides methods such as didUpdateActiveEnergyQuantity
, didUpdateDistanceQuantity
, and didUpdateHeartRateSample
. If you give WorkoutSessionManager an object that acts as a delegate, the manager can delegate UI management to that object using the methods provided by the delegation protocol.
In the principal class, WorkoutSessionManager, define a property to hold a weak reference to the delegate: weak var delegate: WorkoutSessionManagerDelegate?
Then, whenever new samples become available, call the corresponding delegate method. So, for example, in the addActiveEnergySamples
function, you already have the following line: self.delegate?.workoutSessionManager(self, didUpdateActiveEnergyQuantity: self.currentActiveEnergyQuantity)
In the delegate class, DashboardController, adopt the WorkoutSessionManagerDelegate protocol: class DashboardController: WKInterfaceController, WorkoutSessionManagerDelegate
And in awakeWithContext
, assign yourself as the manager's delegate: wSM?.delegate = self
Finally, in the delegate class, implement the methods provided by the delegation protocol, and make such changes to your UI as necessary based on the data passed through those methods.
Call a method from another UIViewController in swift 2.0
You can create a global method. Create a empty swift file and add this code in it:
import Foundation
import AVFoundation
var backgroundMusicPlayer = AVAudioPlayer()
func playBackgroundMusic(filename: String) {
let url = NSBundle.mainBundle().URLForResource(filename, withExtension: nil)
guard let newURL = url else {
print("Could not find file: \(filename)")
return
}
do {
backgroundMusicPlayer = try AVAudioPlayer(contentsOfURL: newURL)
backgroundMusicPlayer.numberOfLoops = -1
backgroundMusicPlayer.prepareToPlay()
backgroundMusicPlayer.play()
} catch let error as NSError {
print(error.description)
}
}
Now when ever you want to play any song just call that method this way:
playBackgroundMusic("yourSong.mp3")
And if you want to go with your class then you can do it this way:
import Foundation
import AVFoundation
var audioPlayer: AVAudioPlayer!
var deviceCurrentTime: NSTimeInterval!
class Song: NSObject {
func playSong() {
let sound = NSBundle.mainBundle().pathForResource("We_Are_One_Ole_Ola_", ofType: "mp3")
let soundData = NSData(contentsOfFile: sound!)
// self.audioPlayer = AVAudioPlayer(data: soundData!) throws
audioPlayer = nil
do {
audioPlayer = try AVAudioPlayer(data: soundData!)
}
catch {
print("Handle \(error) here")
}
let delay:NSTimeInterval = 0.0//100ms
var playtime:NSTimeInterval
playtime = audioPlayer.deviceCurrentTime + delay
audioPlayer?.playAtTime(playtime)
audioPlayer?.play()
}
}
In other class you can use it this way:
override func viewDidLoad() {
super.viewDidLoad()
let temp = Song()
temp.playSong()
}
Related Topics
Uipickerview Selectrow Doesn't Works
Swift 2.0 Keychain Type Errors for Secitemcopymatching
Difference Between Text("") and Text(Verbatim: "") Initializers in Swiftui
Swift Realm Property '*' Has Been Added to Latest Object Model Migration
Lazy Property Initialization in Swift
Swiftui: Is There Exist Modifier to Highlight Substring of Text() View
How to Make Cells Have a Gradient Background
Why Does the Following Code Crash on an iPhone 5 But Not an iPhone 5S
Cross Platform Aes Encryption Between iOS and Kotlin/Java Using Apples Cryptokit
Split Uint32 into [Uint8] in Swift
How to Implement iOServicematchingcallback in Swift
Swift 2.0 'Inout' Function Parameters and Computed Properties
Is the Swift Divide "/" Operator Not Working or Have I Missed Something
How to Open a Screen Directly in Xcuitest
Swiftui - in Sheet Have a Fixed Continue Button That Is Not Scrollable
What Would Be a Proper Storyboard Example of Combining Nav Bars and Tab Bars in One App