Remote Controls in Swift 2.0 (MPNowPlayingInfoCenter) - xcode

I'm trying to make a radio app with Swift. And I have problem with remote controls on the lock screen. Simply doesn't work - nothing on the screen. The code from the ViewController:
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
playButton.setTitle("Play", forState: UIControlState.Normal)
if NSClassFromString("MPNowPlayingInfoCenter") != nil {
let image:UIImage = UIImage(named: "logo_player_background")!
let albumArt = MPMediaItemArtwork(image: image)
var songInfo: NSMutableDictionary = [
MPMediaItemPropertyTitle: "Radio Brasov",
MPMediaItemPropertyArtist: "87,8fm",
MPMediaItemPropertyArtwork: albumArt
]
MPNowPlayingInfoCenter.defaultCenter().nowPlayingInfo = songInfo as [NSObject : AnyObject]
}
if (AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback, error: nil)) {
println("Receiving remote control events")
UIApplication.sharedApplication().beginReceivingRemoteControlEvents()
} else {
println("Audio Session error.")
}
}
Even after fixing MPNowPlayingInfoCenter line, nothing appears on the lock screen. What I'm doing wrong?
the code is from tutorial

Okay, I've fix it. The problem was with part AVAudioSession:
if (AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback, error: nil)) {
println("Receiving remote control events")
UIApplication.sharedApplication().beginReceivingRemoteControlEvents()
} else {
println("Audio Session error.")
I've replaced this with:
try! AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback, withOptions: [])
try! AVAudioSession.sharedInstance().setActive(true)
And remote controls are working :)

Related

fatal error: unexpectedly found nil while unwrapping an Optional value in Swift 2

My app works fine on the simulator but crashes with this message running it on iPhone device. Why and how can I fix it?
How can I find on what code line the app crashes?
func playButton(playButton: UIButton!) {
var image = UIImage()
if activePlayer == 1 { image = UIImage(named: "x.png")! }
else { image = UIImage(named: "o.png")! }
playButton.setImage(image, forState: .Normal)
}
In the code you show, the part where it could generate this error is probably the forced unwrapped UIImage. Modify your code like this to find out:
func playButton(playButton: UIButton!) {
let imageName: String
if activePlayer == 1 {
imageName = "x.png"
} else {
imageName = "o.png"
}
if let image = UIImage(named: imageName) {
playButton.setImage(image, forState: .Normal)
} else {
print("error while retrieving image named '\(imageName)'")
}
}
The IOS device is case sensitive while the simulator isn't. So, I replaced the image names to the exact file names ("X.png" and "O.png" instead of "x.png" and "o.png"). Now, UIImage(named: "X.png") is not nil and the app works fine.
Here, we would use if let and have a look at below
func playButton(playButton: UIButton!) {
var image = UIImage()
if let player = activePlayer {
if player == 1 {
image = UIImage(named: "x.png")! }
} else { image = UIImage(named: "o.png")! }
playButton.setImage(image, forState: .Normal)
}
(or) if you are using Swift 2.0 and Xcode 7, guard is good choice too.

Proper way to reuse NSWindowControllers

This is a follow-up to this question.
I'm trying to create an app with a few windows that pop up on start,
and can be closed ,then opened again later.
I'm not having issues with reopening the windows anymore,
but issues with memory. It keeps going up, everytime I request those windows to show again.
Here is my code:
class AppDelegate: NSObject, NSApplicationDelegate {
var parentWC: NSWindowController?
var childWC: NSWindowController?
func showThem() {
if self.parentWC == nil {
let parentWindow = CustomWindow()
self.parentWC.window = parentWindow
}
if self.childWC == nil {
let childWindow = NSWindow()
self.childWC.window = childWindow
self.parentWC.window.addChildWindow(self.childWC.window)
}
}
func closeAllWindows() {
self.childWC.window.close()
self.parentWC.window.close()
}
// From app menu
#IBAction func showThemAgain(sender: AnyObject) {
self.parentWindow.window = nil
self.parentWC = nil
self.childWindow.window = nil
self.childWC = nil
self.showThem()
}
}
class CustomWindow: NSWindow {
func onCloseRequest() {
let appD = (NSApplication.sharedApplication().delegate) as! AppDelegate
appD.closeAllWindows()
}
}
If I'm closing the windows and settings the vars to nil, what is causing the memory usage to go up every time I show these windows? Are they not being closed?
*Note that there is a button in CustomWindow that is used for closing.

Send email In-game using sprite kit in xcode 7 beta3?

I am making an iPad game in sprite kit using swift in xcode 7beta3 and I want the results of the game to be send to the users email after the game is completed. The user should press a button called send and redirect to where they can type in their email-address and send the message. But I have no idea how to make and send an email.
I have been searching all around the internet for an answer to this question, but all are older version answers. I hope you can help.
Thanks in advance
EDIT:
I have been searching some more and i found a solution (here: http://kellyegan.net/sending-files-using-swift/), but I still have a problem. In my GameViewController i have added:
override func viewDidLoad() {
super.viewDidLoad()
let scene = StartGameScene(size: view.bounds.size)
let skView = view as! SKView
skView.showsFPS = true
skView.showsNodeCount = true
skView.ignoresSiblingOrder = true
scene.scaleMode = .ResizeFill
skView.presentScene(scene)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
internal func sendEmail() {
//Check to see the device can send email.
if( MFMailComposeViewController.canSendMail() ) {
print("Can send email.")
let mailComposer = MFMailComposeViewController()
mailComposer.mailComposeDelegate = self
//Set the subject and message of the email
mailComposer.setSubject("Have you heard a swift?")
mailComposer.setMessageBody("This is what they sound like.", isHTML: false)
if let filePath = NSBundle.mainBundle().pathForResource("Math", ofType: "txt") {
print("File path loaded.")
if let fileData = NSData(contentsOfFile: filePath) {
print("File data loaded.")
mailComposer.addAttachmentData(fileData, mimeType: "text/plain", fileName: "Math")
}
}
self.presentViewController(mailComposer, animated: true, completion: nil)
}
}
func mailComposeController(controller: MFMailComposeViewController, didFinishWithResult result: MFMailComposeResult, error: NSError?) {
self.dismissViewControllerAnimated(true, completion: nil)
}
The sendMail() is called in one of my gameScenes when you press a button.
The problem is that I get an error when I press that button. It prints out
Can send email.
File path loaded.
File data loaded.
as it should, but then it gives an error:
Could not cast value of type 'UIView' (0x1964ea508) to 'SKView' (0x19624f560).
I think the problem is the self.presentViewController(), but I have no idea how to fix it.

GameCenter not working, authentication and leaderboard not showing

With Swift 2, GameCenter is not working for me. The authentication ViewController is not showing up... Here is my func authenticateLocalPlayer():
func authenticateLocalPlayer() {
var localPlayer = GKLocalPlayer()
localPlayer.authenticateHandler = {(viewController: UIViewController?, error: NSError?) -> Void in
if (viewController != nil) {
self.presentViewController(viewController!, animated: true, completion: nil)
print("Not Authenticated. ")
} else {
print("Authenticated. ")
}
}
}
It is returning "Not Authenticated" every time, but is not presenting the ViewController. Any solution?
This solution presents the viewController correctly using Swift 2 in Xcode 7.0.
Note that I have changed the code before the if statement begins. I believe the syntax may have changed in a recent software update as I had this problem too.
In my app I called authenticateLocalPlayer() in the viewDidLoad() method of the GameViewController class.
func authenticateLocalPlayer() {
let localPlayer = GKLocalPlayer.localPlayer()
localPlayer.authenticateHandler = {(viewController, error) -> Void in
if (viewController != nil) {
self.presentViewController(viewController!, animated: true, completion: nil)
}
else {
print((GKLocalPlayer.localPlayer().authenticated))
}
}
}

AVPlayerItem videoComposition freeze IOS8

I am playing a AVMutableVideoComposition with AVPlayer and since IOS8 everything was perfectly fine.
But now the video start playing and after 4 or 5 seconds it stop ,like buffering or something like that, the sound keeps playing and when the video ends the AVPlayer loops and play it fine without stops.
I have no clue for fixing this issue.
Any help would be appreciate,
Thank you
I had a same issue, but I got the solution.
You should play after playerItem's status is changed to .ReadyToPlay.
I also answered here, that issue is similar to your issue.
Please see as below.
func startVideoPlayer() {
let playerItem = AVPlayerItem(asset: self.composition!)
playerItem.videoComposition = self.videoComposition!
let player = AVPlayer(playerItem: playerItem)
player.actionAtItemEnd = .None
videoPlayerLayer = AVPlayerLayer(player: player)
videoPlayerLayer!.frame = self.bounds
/* add playerItem's observer */
player.addObserver(self, forKeyPath: "player.currentItem.status", options: .New, context: nil)
NSNotificationCenter.defaultCenter().addObserver(self, selector: "playerItemDidReachEnd:", name: AVPlayerItemDidPlayToEndTimeNotification, object: playerItem);
self.layer.addSublayer(videoPlayerLayer!)
}
override func observeValueForKeyPath(keyPath: String?, ofObject object: AnyObject?, change: [String : AnyObject]?, context: UnsafeMutablePointer<Void>) {
if keyPath != nil && keyPath! == "player.currentItem.status" {
if let newValue = change?[NSKeyValueChangeNewKey] {
if AVPlayerStatus(rawValue: newValue as! Int) == .ReadyToPlay {
playVideo() /* play after status is changed to .ReadyToPlay */
}
}
} else {
super.observeValueForKeyPath(keyPath, ofObject: object, change: change, context: context)
}
}
func playerItemDidReachEnd(notification: NSNotification) {
let playerItem = notification.object as! AVPlayerItem
playerItem.seekToTime(kCMTimeZero)
playVideo()
}
func playVideo() {
videoPlayerLayer?.player!.play()
}
Same here, don't know if it can be count like an answer but anyway, just use
[AVPlayer seekToTime:AVPlayer.currentItem.duration]; to make first loop by yourself and to avoid AVPlayer stop. That's only way that i found.
I was having the same problem and i solved it this way ..
Instead of applying videoComposition to AVPlayerItem directly .. i exported my video using AVAssetExportSession to apply videoComposition, which in turn gives me a Url with a video having all my videoComposition applied and now i can use this contentURL to play video on AVPlayer..
This works like a charm ..
Exporting video will take time but as now rendering video composition is not happening on the go, it will work smoothly..
Following code can be used to export video ..
AVAssetExportSession *export = [[AVAssetExportSession alloc] initWithAsset:asset presetName:AVAssetExportPreset1280x720];
export.videoComposition = videoComposition;
export.outputURL = [NSURL fileURLWithPath:[[NSTemporaryDirectory() stringByAppendingPathComponent:[NSUUID new].UUIDString] stringByAppendingPathExtension:#"MOV"]];
export.outputFileType = AVFileTypeQuickTimeMovie;
export.shouldOptimizeForNetworkUse = YES;
[export exportAsynchronouslyWithCompletionHandler:^{
dispatch_async(dispatch_get_main_queue(), ^{
if (export.status == AVAssetExportSessionStatusCompleted) {
completionHander(export.outputURL, nil);
} else {
completionHander(nil, export.error);
}
});
}];

Resources