AVMIDIPlayer leaks memory - swift

I would like to play a MIDI file on iOS 8.2 with AVMIDIPlayer.
This does work indeed, but for a very short number of times: the memory seems never to be freed, and it is eventually filled.
Below is my code in Swift 1.2, reduced to a bare minimum: everything takes place in the ViewController, there are no other classes, no delegates, no error checking, etc.
The interface has just three buttons: NEW (instantiates a new AVMIDIPlayer and prerolls), PLAY, STOP.
This memory problem happens on the Simulator and on an actual device, and the bigger the soundfont and the midifile, the worse it is.
I noticed that RAM grows when creating a new AVMIDIPlayer instance AND when playing the midifile (in the latter case you can get even +4Mb/sec).
What am I missing?
Thanks for your help.
import UIKit
import AVFoundation
class ViewController: UIViewController {
var mp:AVMIDIPlayer?
#IBAction func newButton(sender: AnyObject) {
mp = AVMIDIPlayer(contentsOfURL: NSBundle.mainBundle().URLForResource("ahVous", withExtension:"mid"),
soundBankURL: NSBundle.mainBundle().URLForResource("TimGM6mb", withExtension:"sf2"),
error: nil)
mp!.prepareToPlay()
}
#IBAction func playButton(sender: AnyObject) {
mp!.play(nil)
}
#IBAction func stopButton(sender: AnyObject) {
mp!.stop()
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}

Related

Swift read file cause memory usage increase. Is it a leak?

I am reading a file from disk on Mac. The following code in a function keeps making memory usage go up. I don't have any variable to reference the "content", just test to read it in and think the system will release it after the function exit. but it does not. System actually only releases the memory when the for-loop is done.
My question is, how to let system to release the "content" object after the read function exits? I even delay 10s after the function call in the loop.
import Cocoa
class ViewController: NSViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override var representedObject: Any? {
didSet {
// Update the view, if already loaded.
}
}
#IBAction func onRead(_ sender: NSButton) {
for n in 0..<100
{
readFile()
sleep(10)//not enough time for system to recycle the memory??
}
}
func readFile()
{
print ("test read file")
let content = FileManager.default.contents(atPath: "/Users/swiftuser/Documents/testfile.txt")
}
}

setScreenname() only fires after logEvent()

I try to use Firebase to track my app. Here's my code:
import UIKit
import Firebase
class Section1121: UIViewController {
override func loadView() {
super.loadView()
Analytics.setScreenName("Screen1.1.2.1", screenClass: "Section1121")
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(true)
// Do any additional setup after loading the view.
Analytics.logEvent(AnalyticsEventAddToCart, parameters: nil)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
I expect following order:
1: default screen_view event fires, without changing screen name
2: setScreenname fires and changes the screen name
3: logevent fires, sending add_to_cart event with new screen name
But actual order on debug view is 1 -> 3 -> 2, and add_to_cart is logged without new screen name.
Here's the screenshot of debug view.
In the code setScreenname is definitely before logEvent, but why the firing order has changed?
Can I make it fire before logEvent?
Following adbitx's advice, I moved setScreenName to viewDidAppear just before logEvent, and the code seems to work properly.

How to pass a string between viewcontrollers with out the use of a SEGUE

Recently I have been making a app where you can create and quiz yourself on definitions or anything for that matter. I pass data to the next view after it the user hits the create button to make the title of the new notecard. The code I am using right now for that is:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
let DestViewController: Card1 = segue.destinationViewController as! Card1
DestViewController.Content = Notetitle.text!
self.saved = self.Notetitle.text!
}
All of that works but, it will only work if I have a segue between viewcontrollers. I need to be able to pass that data with out a segue because I want the user to be able to create as many notecards as they want and the way I am trying to do that now is by using this code to make a copy of the UIView and then put in the new data (a master view). The new view can only be create using an IBAction. The prepare for segue I cannot use in the IBAction because it is it's own override function.
This is the code I am using to make a the new view:
let newCard =
self.storyboard!.instantiateViewControllerWithIdentifier("Main")
self.presentViewController(newCard, animated: true, completion:nil)
My hope is that I will be able to make a new view and then pass in the data pass in the data that the user just made to go on the notecard. (Hope this makes any sense at all)
MAIN TOPICS: -Create a new view and pass in new data Problem: Can pass data without a segue dont have one :/ -Be able to pass data between view controllers without a segue :)
I am new to all of this about 5 months. All of my code is in swift. Take it easy on me please. Feel free to ask me with any questions or comments. I have already posted a question on this but I didnt get an answer so have at it.
Thanks, Lucas Mazza
Don't use global variables unless you really need to. Making global static singleton's does not follow best practices. For more information read: What is so bad about singletons?
A better solution
You can use the protocol delegate pattern. I've actually written an article on this topic here:
https://www.codebeaulieu.com/36/Passing-data-with-the-protocol-delegate-pattern
You'll need a protocol that defines a function that will accept data. Then your other view controller will need to implement the delegate. If you need step-by-step details see the link provided above, alternatively you can simply download the project below and examine the code.
Download Working Example Project
Here's the code to make your protocol-delegate pattern work:
View Controller 1:
class ViewController: UIViewController, PresentedViewControllerDelegate {
#IBOutlet weak var textOutlet: UILabel!
#IBAction func doPresent(sender: AnyObject) {
let pvc = storyboard?.instantiateViewControllerWithIdentifier("PresentedViewController") as! PresentedViewController
pvc.data = "important data sent via delegate!"
pvc.delegate = self
self.presentViewController(pvc, animated: true, completion: nil)
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func acceptData(data: AnyObject!) {
self.textOutlet.text = "\(data!)"
}
}
View Controller 2:
import UIKit
// place the protocol in the view controller that is being presented
protocol PresentedViewControllerDelegate {
func acceptData(data: AnyObject!)
}
class PresentedViewController: UIViewController {
// create a variable that will recieve / send messages
// between the view controllers.
var delegate : PresentedViewControllerDelegate?
// another data outlet
var data : AnyObject?
#IBOutlet weak var textFieldOutlet: UITextField!
#IBAction func doDismiss(sender: AnyObject) {
if textFieldOutlet.text != "" {
self.presentingViewController!.dismissViewControllerAnimated(true, completion: nil)
}
}
override func viewDidLoad() {
super.viewDidLoad()
print("\(data!)")
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func viewWillDisappear(animated: Bool) {
super.viewWillDisappear(animated)
if self.isBeingDismissed() {
self.delegate?.acceptData(textFieldOutlet.text)
}
}
}

Swift: I get Debugging "errors" when I try to make my program work

I followed an online tutorial on youtube for a Hello World like program for Swift. Even though I typed the code just like the code in the tutorial it till gives me a debugging error (the green errors). I researched problems like this but the code was to complicated and was over my head. Usually I code in java, but I have been wanting to develop for mobile. Anyways, if you can tell me:
1. What the error means.
2. How I can fix it.
3. How can I prevent errors like this.
NameLabel.text = "Hi (nameTextField.text)" is the line I get the error on.
Here is my code:
import UIKit
class ViewController: UIViewController {
#IBOutlet var NameLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func HelloWorldAction(nameTextField: UITextField) {
NameLabel.text = "Hi \(nameTextField.text)"
}
}
nameTextField is't #IBAction. It's #IBOutlet.
I made a button and it appropriated action. I have everything working.
#IBAction func button(sender: UIButton!) {
NameLabel.text = "Hi \(namedTextField.text)"
}

Having trouble with camera IOS8 / Swift with Card.IO

When I try and scan a card with Card.IO. it does not bring up the camera let alone the green lines around it. When I run this code and press the button it does not show the camera in the view controller. Any ideas ? The sample works fine in io8 in obj-C .
#IBAction func PressScan(sender: AnyObject) {
var CardScanner : CardIOPaymentViewController = CardIOPaymentViewController()
CardScanner.modalPresentationStyle = UIModalPresentationStyle.FullScreen
self.presentViewController(CardScanner, animated: true, completion: nil)
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
CardIOPaymentViewController.preload()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func userDidProvideCreditCardInfo(cardInfo: CardIOCreditCardInfo!, inPaymentViewController paymentViewController: CardIOPaymentViewController!) {
}
func userDidCancelPaymentViewController(paymentViewController: CardIOPaymentViewController!) {
}
Is there something in the plist file I need to amend to allow camera access for iOS8 ?
Solution is here: https://github.com/card-io/card.io-iOS-SDK/issues/76#issuecomment-65856792
Namely:
You are not initializing CardIOPaymentViewController correctly. It should be
var CardScanner : CardIOPaymentViewController = CardIOPaymentViewController(paymentDelegate: self)