Sound through UIButton does not work, swift - swift

I have 4 buttons that trigger 4 different sounds. All buttons work, I have a println button 1, button2, etc.. For some reason I am only hearing sounds that come through button 3 and 4. I used the same coding method for all buttons and audio players, So I have no idea what the problem could be. This is my code.
There are no errors or anything and again all buttons and audio players work the same, so I'm not sure why button 1 and 2 don't work.
Any help would be much appreciated.
class MusicPlayer {
var onePlayer : AVAudioPlayer?
var twoPlayer : AVAudioPlayer?
var threePlayer : AVAudioPlayer?
var fourPlayer : AVAudioPlayer?
func playOneSound() {
twoPlayer!.play()
}
func playTwoSound() {
twoPlayer!.play()
}
func playThreeSound() {
threePlayer!.play()
}
func playFourSound() {
fourPlayer!.play()
}
func stopOneSound() {
twoPlayer!.stop()
}
func stopTwoSound() {
twoPlayer!.stop()
}
func stopThreeSound() {
threePlayer!.stop()
}
func stopFourSound() {
fourPlayer!.stop()
}
class var sharedInstance: MusicPlayer {
struct Static {
static var instance: MusicPlayer?
static var token: dispatch_once_t = 0
}
dispatch_once(&Static.token) {
Static.instance = MusicPlayer()
}
return Static.instance!
}
init() {
// Create an NSURL for the correct file
let oneSound = NSURL(fileURLWithPath: NSBundle.mainBundle().pathForResource("Go To Sleep 1", ofType: "mp3")!)
let twoSound = NSURL(fileURLWithPath: NSBundle.mainBundle().pathForResource("Go To Sleep 2", ofType: "mp3")!)
let threeSound = NSURL(fileURLWithPath: NSBundle.mainBundle().pathForResource("Go To Sleep 3", ofType: "mp3")!)
let fourSound = NSURL(fileURLWithPath: NSBundle.mainBundle().pathForResource("Go To Sleep 5", ofType: "mp3")!)
// Create a new AVAudioPlayer with the correct file
onePlayer = AVAudioPlayer(contentsOfURL: oneSound, error: nil)
twoPlayer = AVAudioPlayer(contentsOfURL: twoSound, error: nil)
threePlayer = AVAudioPlayer(contentsOfURL: threeSound, error: nil)
fourPlayer = AVAudioPlayer(contentsOfURL: fourSound, error: nil)
/*onePlayer!.volume = masterEffectSoundLevel
twoPlayer!.volume = masterEffectSoundLevel
threePlayer!.volume = masterEffectSoundLevel
fourPlayer!.volume = masterEffectSoundLevel*/
// Prepare for playback, set loop count to infinite, start playback
onePlayer!.prepareToPlay()
twoPlayer!.prepareToPlay()
threePlayer!.prepareToPlay()
fourPlayer!.prepareToPlay()
}
This is my code for the buttons :
#IBAction func settingOneButton(sender: UIButton) {
settingOne.hidden = false
settingTwo.hidden = true
settingThree.hidden = true
settingFour.hidden = true
}
#IBAction func settingTwoButton(sender: UIButton) {
settingOne.hidden = true
settingTwo.hidden = false
settingThree.hidden = true
settingFour.hidden = true
}
#IBAction func settingThreeButton(sender: UIButton) {
settingOne.hidden = true
settingTwo.hidden = true
settingThree.hidden = false
settingFour.hidden = true
}
#IBAction func settingFourButton(sender: UIButton) {
settingOne.hidden = true
settingTwo.hidden = true
settingThree.hidden = true
settingFour.hidden = false
}
#IBAction func goToSleepPressed(sender: AnyObject) {
if settingOne.hidden == false {
MusicPlayer.sharedInstance.playOneSound()
MusicPlayer.sharedInstance.stopTwoSound()
MusicPlayer.sharedInstance.stopThreeSound()
MusicPlayer.sharedInstance.stopFourSound()
println("one")
} else if settingTwo.hidden == false {
MusicPlayer.sharedInstance.playTwoSound()
MusicPlayer.sharedInstance.stopOneSound()
MusicPlayer.sharedInstance.stopThreeSound()
MusicPlayer.sharedInstance.stopFourSound()
println("two")
} else if settingThree.hidden == false {
MusicPlayer.sharedInstance.playThreeSound()
MusicPlayer.sharedInstance.stopOneSound()
MusicPlayer.sharedInstance.stopTwoSound()
MusicPlayer.sharedInstance.stopFourSound()
println("three")
} else if settingFour.hidden == false {
MusicPlayer.sharedInstance.playFourSound()
MusicPlayer.sharedInstance.stopOneSound()
MusicPlayer.sharedInstance.stopTwoSound()
MusicPlayer.sharedInstance.stopThreeSound()
println("four")
}
}

I figured out what the problem was. I had twoPlayer both in playOneSound() and playTwoSound().

Related

Swift - Visionkit How to edit the color of the buttons "Keep Scan" and "Retake"

I have a problem.
I've implemented the visionkit framework in order to detect a text when the camera is used.
The problem is that the colors of the buttons: "Keep Scan" and "Retake" are blue. I want them in black color. How can I fix this problem? I paste my code.
Thank you in advance!
import UIKit
import Vision
import VisionKit
class ScanText: UIViewController, VNDocumentCameraViewControllerDelegate {
#IBOutlet weak var imageView: UIImageView!
#IBOutlet weak var TextScan: UITextView!
#IBOutlet weak var buttonStartShape: UIButton!
#IBOutlet weak var infoScattaUnaFoto: UILabel!
#IBOutlet weak var copyButtonShape: UIButton!
var textRecognitionRequest = VNRecognizeTextRequest(completionHandler: nil)
private let textRecognitionWorkQueue = DispatchQueue(label: "MyVisionScannerQueue", qos: .userInitiated, attributes: [], autoreleaseFrequency: .workItem)
var classView = ViewController()
var arrayText = String()
override func viewDidLoad() {
super.viewDidLoad()
imageView.layer.cornerRadius = 15
imageView.clipsToBounds = true
TextScan.layer.cornerRadius = 15
TextScan.clipsToBounds = true
copyButtonShape.layer.cornerRadius = 25
copyButtonShape.clipsToBounds = true
buttonStartShape.layer.cornerRadius = 25
buttonStartShape.clipsToBounds = true
TextScan.isEditable = true
setupVision()
}
#IBAction func TakePicture(_ sender: Any) {
let scannerViewController = VNDocumentCameraViewController()
scannerViewController.delegate = self
present(scannerViewController, animated: true)
}
private func setupVision() {
textRecognitionRequest = VNRecognizeTextRequest { (request, error) in
guard let observations = request.results as? [VNRecognizedTextObservation] else { return }
var detectedText = ""
for observation in observations {
guard let topCandidate = observation.topCandidates(2).first else { return }
print("text \(topCandidate.string) has confidence \(topCandidate.confidence)")
detectedText += topCandidate.string
detectedText += "\n"
}
DispatchQueue.main.async {
self.TextScan.isHidden = false
self.infoScattaUnaFoto.isHidden = true
self.copyButtonShape.isHidden = false
self.buttonStartShape.setTitle("Ripeti", for: .normal)
self.TextScan.text += detectedText
self.TextScan.flashScrollIndicators()
}
}
textRecognitionRequest.recognitionLevel = .accurate
}
private func processImage(_ image: UIImage) {
imageView.image = image
recognizeTextInImage(image)
}
private func recognizeTextInImage(_ image: UIImage) {
guard let cgImage = image.cgImage else { return }
TextScan.text = ""
textRecognitionWorkQueue.async {
let requestHandler = VNImageRequestHandler(cgImage: cgImage, options: [:])
do {
try requestHandler.perform([self.textRecognitionRequest])
} catch {
print(error)
}
}
}
func documentCameraViewController(_ controller: VNDocumentCameraViewController, didFinishWith scan: VNDocumentCameraScan) {
/* guard scan.pageCount >= 1 else {
controller.dismiss(animated: true)
return
}*/
for i in 0 ..< scan.pageCount {
let img = scan.imageOfPage(at: i)
processImage(img)
}
let originalImage = scan.imageOfPage(at: 0)
print(originalImage)
//let newImage = compressedImage(originalImage)
controller.dismiss(animated: true)
}
func documentCameraViewController(_ controller: VNDocumentCameraViewController, didFailWithError error: Error) {
print(error)
controller.dismiss(animated: true)
}
func documentCameraViewControllerDidCancel(_ controller: VNDocumentCameraViewController) {
controller.dismiss(animated: true)
}
func compressedImage(_ originalImage: UIImage) -> UIImage {
guard let imageData = originalImage.jpegData(compressionQuality: 1),
let reloadedImage = UIImage(data: imageData) else {
return originalImage
}
return reloadedImage
}
//MARK: By tapping on this button, I pass all the data.
#IBAction func CopyText(_ sender: Any) {
let vc = (storyboard?.instantiateViewController(identifier: "SpeakDetail") as? ViewController)!
vc.textscannerized = TextScan.text
self.navigationController?.pushViewController(vc, animated: true)
}
}
You can try something like this:
scannerViewController.view.tintColor = .red

Why does my segue not wait until completion handler finished?

I have a page based app, using RootViewController, ModelViewController, DataViewController, and a SearchViewController.
In my searchViewController, I search for an item and then add or remove that Item to an array which is contained in a Manager class(and UserDefaults), which the modelViewController uses to instantiate an instance of DataViewController with the correct information loaded using the dataObject. Depending on whether an Item was added or removed, I use a Bool to determine which segue was used, addCoin or removeCoin, so that the RootViewController(PageView) will show either the last page in the array, (when a page is added) or the first (when removed).
Everything was working fine until I ran into an error which I can not diagnose, the problem is that when I add a page, the app crashes, giving me a "unexpectadely found nil when unwrapping an optional value"
This appears to be the problem function, in the searchViewController 'self.performSegue(withIdentifier: "addCoin"' seems to be called instantly, even without the dispatchque:
#objc func addButtonAction(sender: UIButton!) {
print("Button tapped")
if Manager.shared.coins.contains(dataObject) {
Duplicate()
} else if Manager.shared.coins.count == 5 {
max()
} else {
Manager.shared.addCoin(coin: dataObject)
CGPrices.shared.getData(arr: true, completion: { (success) in
print(Manager.shared.coins)
DispatchQueue.main.async {
self.performSegue(withIdentifier: "addCoin", sender: self)
}
})
}
searchBar.text = ""
}
Meaning that In my DataViewController, this function will find nil:
func getIndex() {
let index = CGPrices.shared.coinData.index(where: { $0.id == dataObject })!
dataIndex = index
}
I can't find out why it does not wait for completion.
I also get this error about threads:
[Assert] Cannot be called with asCopy = NO on non-main thread.
which is why I try to do the push segue using dispatch que
Here is my searchViewController full code:
import UIKit
class SearchViewController: UIViewController, UISearchBarDelegate {
let selectionLabel = UILabel()
let searchBar = UISearchBar()
let addButton = UIButton()
let removeButton = UIButton()
var filteredObject: [String] = []
var dataObject = ""
var isSearching = false
//Add Button Action.
#objc func addButtonAction(sender: UIButton!) {
print("Button tapped")
if Manager.shared.coins.contains(dataObject) {
Duplicate()
} else if Manager.shared.coins.count == 5 {
max()
} else {
Manager.shared.addCoin(coin: dataObject)
CGPrices.shared.getData(arr: true, completion: { (success) in
print(Manager.shared.coins)
DispatchQueue.main.async {
self.performSegue(withIdentifier: "addCoin", sender: self)
}
})
}
searchBar.text = ""
}
//Remove button action.
#objc func removeButtonActon(sender: UIButton!) {
print("Button tapped")
if Manager.shared.coins.contains(dataObject) {
Duplicate()
} else if Manager.shared.coins.count == 5 {
max()
} else {
Manager.shared.removeCoin(coin: dataObject)
self.performSegue(withIdentifier: "addCoin", sender: self)
}
searchBar.text = ""
}
//Prepare for segue, pass removeCoinSegue Bool depending on remove or addCoin.
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "addCoin" {
if let destinationVC = segue.destination as? RootViewController {
destinationVC.addCoinSegue = true
}
} else if segue.identifier == "addCoin" {
if let destinationVC = segue.destination as? RootViewController {
destinationVC.addCoinSegue = false
}
}
}
//Remove button action.
#objc func removeButtonAction(sender: UIButton!) {
if Manager.shared.coins.count == 1 {
removeAlert()
} else {
Manager.shared.removeCoin(coin: dataObject)
print(Manager.shared.coins)
print(dataObject)
searchBar.text = ""
self.removeButton.isHidden = true
DispatchQueue.main.async {
self.performSegue(withIdentifier: "removeCoin", sender: self)
}
}
}
//Search/Filter the struct from CGNames, display both the Symbol and the Name but use the ID as dataObject.
func filterStructForSearchText(searchText: String, scope: String = "All") {
if !searchText.isEmpty {
isSearching = true
filteredObject = CGNames.shared.coinNameData.filter {
// if you need to search key and value and include partial matches
// $0.key.contains(searchText) || $0.value.contains(searchText)
// if you need to search caseInsensitively key and value and include partial matches
$0.name.range(of: searchText, options: .caseInsensitive) != nil || $0.symbol.range(of: searchText, options: .caseInsensitive) != nil
}
.map{ $0.id }
} else {
isSearching = false
print("NoText")
}
}
//Running filter function when text changes.
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
filterStructForSearchText(searchText: searchText)
if isSearching == true && filteredObject.count > 0 {
addButton.isHidden = false
dataObject = filteredObject[0]
selectionLabel.text = dataObject
if Manager.shared.coins.contains(dataObject) {
removeButton.isHidden = false
addButton.isHidden = true
} else {
removeButton.isHidden = true
addButton.isHidden = false
}
} else {
addButton.isHidden = true
removeButton.isHidden = true
selectionLabel.text = "e.g. btc/bitcoin"
}
}
override func viewDidLoad() {
super.viewDidLoad()
//Setup the UI.
self.view.backgroundColor = .gray
setupView()
}
override func viewDidLayoutSubviews() {
}
//Hide keyboard
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
self.view.endEditing(true)
}
//Alerts
func removeAlert() {
let alertController = UIAlertController(title: "Can't Remove", message: "\(dataObject) can't be deleted, add another to delete \(dataObject)", preferredStyle: .alert)
alertController.addAction(UIAlertAction(title: "Okay", style: .default, handler: nil))
self.present(alertController, animated: true, completion: nil)
}
func Duplicate() {
let alertController = UIAlertController(title: "Duplicate", message: "\(dataObject) is already in your pages!", preferredStyle: .alert)
alertController.addAction(UIAlertAction(title: "Okay", style: .default, handler: nil))
self.present(alertController, animated: true, completion: nil)
}
func max() {
let alertController = UIAlertController(title: "Maximum Reached", message: "\(dataObject) can't be added, you have reached the maximum of 5 coins. Please delete a coin to add another.", preferredStyle: .alert)
alertController.addAction(UIAlertAction(title: "Okay", style: .default, handler: nil))
self.present(alertController, animated: true, completion: nil)
}
}
and here is the DataViewController
import UIKit
class DataViewController: UIViewController {
#IBOutlet weak var dataLabel: UILabel!
//Variables and Objects.
//The dataObject carries the chosen cryptocurrencies ID from the CoinGecko API to use to get the correct data to load on each object.
var dataObject = String()
//The DefaultCurrency (gbp, eur...) chosen by the user.
var defaultCurrency = ""
//The Currency Unit taken from the exchange section of the API.
var currencyUnit = CGExchange.shared.exchangeData[0].rates.gbp.unit
var secondaryUnit = CGExchange.shared.exchangeData[0].rates.eur.unit
var tertiaryUnit = CGExchange.shared.exchangeData[0].rates.usd.unit
//Index of the dataObject
var dataIndex = Int()
//Objects
let cryptoLabel = UILabel()
let cryptoIconImage = UIImageView()
let secondaryPriceLabel = UILabel()
let mainPriceLabel = UILabel()
let tertiaryPriceLabel = UILabel()
//Custom Fonts.
let customFont = UIFont(name: "AvenirNext-Heavy", size: UIFont.labelFontSize)
let secondFont = UIFont(name: "AvenirNext-BoldItalic" , size: UIFont.labelFontSize)
//Setup Functions
//Get the index of the dataObject
func getIndex() {
let index = CGPrices.shared.coinData.index(where: { $0.id == dataObject })!
dataIndex = index
}
//Label
func setupLabels() {
//cryptoLabel from dataObject as name.
cryptoLabel.text = CGPrices.shared.coinData[dataIndex].name
//Prices from btc Exchange rate.
let btcPrice = CGPrices.shared.coinData[dataIndex].current_price!
let dcExchangeRate = CGExchange.shared.exchangeData[0].rates.gbp.value
let secondaryExchangeRate = CGExchange.shared.exchangeData[0].rates.eur.value
let tertiaryExchangeRate = CGExchange.shared.exchangeData[0].rates.usd.value
let realPrice = (btcPrice * dcExchangeRate)
let secondaryPrice = (btcPrice * secondaryExchangeRate)
let tertiaryPrice = (btcPrice * tertiaryExchangeRate)
secondaryPriceLabel.text = "\(secondaryUnit)\(String((round(1000 * secondaryPrice) / 1000)))"
mainPriceLabel.text = "\(currencyUnit)\(String((round(1000 * realPrice) /1000)))"
tertiaryPriceLabel.text = "\(tertiaryUnit)\(String((round(1000 * tertiaryPrice) / 1000)))"
}
//Image
func getIcon() {
let chosenImage = CGPrices.shared.coinData[dataIndex].image
let remoteImageUrl = URL(string: chosenImage)
guard let url = remoteImageUrl else { return }
URLSession.shared.dataTask(with: url) { (data, response, err) in
guard let data = data else { return }
do {
DispatchQueue.main.async {
self.cryptoIconImage.image = UIImage(data: data)
}
}
}.resume()
}
override func viewDidLoad() {
super.viewDidLoad()
// for family in UIFont.familyNames.sorted() {
// let names = UIFont.fontNames(forFamilyName: family)
// print("Family: \(family) Font names: \(names)")
// }
// Do any additional setup after loading the view, typically from a nib.
self.setupLayout()
self.getIndex()
self.setupLabels()
self.getIcon()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.dataLabel!.text = dataObject
view.backgroundColor = .lightGray
}
}
Edit: CGPrices Class with getData method:
import Foundation
class CGPrices {
struct Coins: Decodable {
let id: String
let name: String
let symbol: String
let image: String
let current_price: Double?
let low_24h: Double?
//let price_change_24h: Double?
}
var coinData = [Coins]()
var defaultCurrency = ""
var coins = Manager.shared.coins
var coinsEncoded = ""
static let shared = CGPrices()
func encode() {
for i in 0..<coins.count {
coinsEncoded += coins[i]
if (i + 1) < coins.count { coinsEncoded += "%2C" }
}
print("encoded")
}
func getData(arr: Bool, completion: #escaping (Bool) -> ()) {
encode()
let urlJSON = "https://api.coingecko.com/api/v3/coins/markets?vs_currency=btc&ids=\(coinsEncoded)"
guard let url = URL(string: urlJSON) else { return }
URLSession.shared.dataTask(with: url) { (data, response, err) in
guard let data = data else { return }
do {
let coinsData = try JSONDecoder().decode([Coins].self, from: data)
self.coinData = coinsData
completion(arr)
} catch let jsonErr {
print("error serializing json: \(jsonErr)")
print(data)
}
}.resume()
}
func refresh(completion: () -> ()) {
defaultCurrency = UserDefaults.standard.string(forKey: "DefaultCurrency")!
completion()
}
}
I figured it out.
The problem was inside my getData method I was not updated the coins array:
var coinData = [Coins]()
var defaultCurrency = ""
var coins = Manager.shared.coins
var coinsEncoded = ""
static let shared = CGPrices()
func encode() {
for i in 0..<coins.count {
coinsEncoded += coins[i]
if (i+1)<coins.count { coinsEncoded+="%2C" }
}
print("encoded")
}
I needed to add this line in getData:
func getData(arr: Bool, completion: #escaping (Bool) -> ()) {
//Adding this line to update the array so that the URL is appended correctly.
coins = Manager.shared.coins
encode()
let urlJSON = "https://api.coingecko.com/api/v3/coins/markets?vs_currency=btc&ids=\(coinsEncoded)"
This would fix the finding nil in the DataViewController, but the app would still crash do to updating UI Elements on a background thread, as the segue was called inside the completion handler of the getData method. to fix this, I used DispatchQue.Main.Async on the segue inside the getData method in the addButton function, to ensure that everything is updated on the main thread, like so:
#objc func addButtonAction(sender: UIButton!) {
print("Button tapped")
if Manager.shared.coins.contains(dataObject) {
Duplicate()
} else if Manager.shared.coins.count == 5 {
max()
} else {
Manager.shared.addCoin(coin: dataObject)
print("starting")
CGPrices.shared.getData(arr: true) { (arr) in
print("complete")
print(CGPrices.shared.coinData)
//Here making sure it is updated on main thread.
DispatchQueue.main.async {
self.performSegue(withIdentifier: "addCoin", sender: self)
}
}
}
searchBar.text = ""
}
Thanks for all the comments as they helped me to figure this out, and I learned a lot in doing so. Hopefully this can help someone else in their thought process when debugging, as one can get so caught up in one area of a problem, and forget to take a step back and look to other areas.

How to clear the information from the Label.text?

I am developing a QR code reader application. Hier is my code:
var captureSession: AVCaptureSession?
var videoPreviewLayer: AVCaptureVideoPreviewLayer?
var qrCodeframeView: UIView?
#IBOutlet weak var CancelButton: UIButton!
#IBOutlet weak var Label: UILabel!
override func viewDidLoad() {
CancelButton.hidden = true
Label.hidden = true
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 ScanMe(sender: AnyObject) {
CancelButton.hidden = false
Label.hidden = false
let captureDevice = AVCaptureDevice.defaultDeviceWithMediaType(AVMediaTypeVideo)
var error: NSError?
let input: AnyObject!
do {
input = try AVCaptureDeviceInput (device: captureDevice)
} catch let error1 as NSError{
error = error1
input = nil
}
if (error != nil){
print ("\(error?.localizedDescription)")
return
}
captureSession = AVCaptureSession()
captureSession?.addInput(input as! AVCaptureInput)
let captureMetadatOutput = AVCaptureMetadataOutput()
captureSession?.addOutput(captureMetadatOutput)
captureMetadatOutput.setMetadataObjectsDelegate(self, queue: dispatch_get_main_queue())
captureMetadatOutput.metadataObjectTypes = [AVMetadataObjectTypeQRCode]
videoPreviewLayer = AVCaptureVideoPreviewLayer(session: captureSession)
videoPreviewLayer?.videoGravity = AVLayerVideoGravityResizeAspectFill
videoPreviewLayer?.frame = view.layer.bounds
view.layer.addSublayer(videoPreviewLayer!)
captureSession?.startRunning()
view.bringSubviewToFront(Label)
view.bringSubviewToFront(CancelButton)
qrCodeframeView = UIView()
qrCodeframeView?.layer.borderColor = UIColor.greenColor().CGColor
qrCodeframeView?.layer.borderWidth = 2
view.addSubview(qrCodeframeView!)
view.bringSubviewToFront(qrCodeframeView!)
}
func captureOutput(captureOutput: AVCaptureOutput!, didOutputMetadataObjects metadataObjects: [AnyObject]!, fromConnection connection: AVCaptureConnection!) {
if metadataObjects == nil || metadataObjects.count == 0 {
qrCodeframeView?.frame = CGRectZero
Label.text = "No QR code detected"
return
}
let metadateObj = metadataObjects[0] as! AVMetadataMachineReadableCodeObject
if metadateObj.type == AVMetadataObjectTypeQRCode {
let BarcodeObject = videoPreviewLayer?.transformedMetadataObjectForMetadataObject(metadateObj as AVMetadataMachineReadableCodeObject) as! AVMetadataMachineReadableCodeObject
qrCodeframeView?.frame = BarcodeObject.bounds
if metadateObj.stringValue != nil {
Label.text = metadateObj.stringValue
captureSession?.stopRunning()
}
}
}
#IBAction func Cancel(sender: AnyObject) {
CancelButton.hidden = true
Label.hidden = true
captureSession?.stopRunning()
qrCodeframeView?.removeFromSuperview()
videoPreviewLayer?.removeFromSuperlayer()
}
#IBAction func Open(sender: AnyObject) {
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
var PC : SecondSecondViewController = segue.destinationViewController as! SecondSecondViewController
PC.label1 = Label.text!
}
}
The problem is when I click the cancel button and go back to the previous viewcontroller, when I reopen the qr code scanner I see the last scanned code, displayed in the Label.text. Would you please help me how to clear the label and do not display the old code, because these codes must be used only once and if the users see the codes they will be able to use them again.
If you want without adding other callbacks:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
var PC : SecondSecondViewController = segue.destinationViewController as! SecondSecondViewController
PC.label1 = Label.text!
Label.text = ""
}
otherwise you have to catch the unwind segue when you come back from SecondSecondViewController and there set Label.text = ""
Just add this to where you exit from the QR (press cancel):
label.text = ""

How to assign a different audio URL for each reusable cell in Swift

I have 2 (or more) reusable collectionView cell and each one have to play a different audio. My problem is that when the audio1 finish, audio2 file start in the same cell of the audio2. If I manually play on each cell there's no problem, but if I want to play all audio automatically one after the other, all audio are played in the same cell. How I can start the next audio in the next cell if the cell has not yet been created?
Here how I append to array:
func appendToArray() {
for (_, page) in self.resources.enumerate() {
for (index,resource) in page.enumerate() {
print("Passa di qui") // Qui passa
if resource.fileType() == .Audio {
S3Client.sharedInstance.downloadResource(resourceKey: resource.value, completion: { (success, file) in
// let files = String(file)
self.audioURLs.append(file)
/**
if self.audioURLs.count == self.resources.count {
// print("audioURLs \(self.audioURLs[index])")
MediaAudioPlayer.sharedInstance.queueTrack(self.audioURLs)
}
*/
})
}
}
}
}
This is the cellForItemAtIndexPath:
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
case .Audio:
let cell = collectionView.dequeueReusableCellWithReuseIdentifier(MediaAudioCell.kCellIdentifier, forIndexPath: indexPath) as! MediaAudioCell
cell.activityIndicator.startAnimating()
cell.activityIndicator.hidden = false
S3Client.sharedInstance.downloadResource(resourceKey: resource.value, completion: { (success, file) in
if success == true && file != nil {
cell.activityIndicator.stopAnimating()
cell.activityIndicator.hidden = true
cell.audioURL = file!
// Make slider indipendent from cell to another
cell.sliderAudio.tag = indexPath.row
cell.sliderAudio.addTarget(self, action: "sliderChange:", forControlEvents: .ValueChanged)
// print("ArrayURL: \(file)")
// print("CiaoCell : \(self.audioURLs.count)")
// print("Ciaoself.resources.countCell : \(self.resources.count)")
/**
if self.audioURLs.count == self.resources.count {
// print("audioURLs \(self.audioURLs[index])")
let item = self.audioURLs[indexPath.row] print("item: \(item)")
}
if self.audioURLs.count == self.resources.count {
// print("audioURLs \(self.audioURLs[index])")
// MediaAudioPlayer.sharedInstance.queueTrack(self.audioURLs)
}
*/
// Display total audio leinght
let asset = AVURLAsset(URL: file!, options: nil)
let audios = asset.tracksWithMediaType(AVMediaTypeAudio)
if let audios: AVAssetTrack = audios[0] {
let audioDuration:CMTime = audios.timeRange.duration
let seconds:Float64 = CMTimeGetSeconds(audioDuration)
cell.labelAudio.text = cell.stringFromTimeInterval(NSTimeInterval(seconds)) as String
}
}
})
return cell
}
This is part of cell's Class:
override func awakeFromNib() {
super.awakeFromNib()
// Partenza automatica, dopo 2secondi, se Accessibilità su ON
let delayTime = dispatch_time(DISPATCH_TIME_NOW, Int64(2 * Double(NSEC_PER_SEC)))
dispatch_after(delayTime, dispatch_get_main_queue()) {
if self.defaults.boolForKey("AutomaticStart") == true && self.defaults.boolForKey("goBackPressed") == false {
if let audioURL = self.audioURL {
// Set AVAudioSession for recording and playing at the same time
let session = AVAudioSession.sharedInstance()
do {
try session.setCategory(AVAudioSessionCategoryPlayback)
try session.setActive(true)
} catch _ {}
// If audio is playing, do not pass to next if cell is created, but continue to playing.
if MediaAudioPlayer.sharedInstance.player?.playing == true { // Se metto a 'false', ed elimino 'else', non parte in automatico.
} else {
MediaVideoPlayer.sharedInstance.stop()
MediaAudioPlayer.sharedInstance.playPauseAudio(audioURL: audioURL, delegate: self)
}
}
}
}
}
And this is the player class:
class MediaAudioPlayer: NSObject, AVAudioPlayerDelegate {
static let sharedInstance = MediaAudioPlayer()
private var delegate: MediaAudioPlayerDelegate?
var player: AVAudioPlayer?
private var lastURL: NSURL?
private var timer: NSTimer?
internal var sliderTouched: Bool = false
var tracks = Array<NSURL?>()
var currentTrackIndex = 0
override init() {
super.init()
}
// MARK: Setup
func playPauseAudio(audioURL url: NSURL, delegate: MediaAudioPlayerDelegate) {
self.delegate?.playing = true // Set default play button on last delegate
self.delegate = delegate // Save delegate
self.sliderTouched = false
// Setup as new only when this audio has not been already set up
if (self.lastURL == nil) || (url != self.lastURL) {
self.lastURL = url
self.setupAudioSession(category: AVAudioSessionCategoryPlayback)
do { // Setup Player
self.player = try AVAudioPlayer(contentsOfURL: url)
} catch _ {}
self.player?.delegate = self
self.player?.prepareToPlay()
timer = NSTimer.scheduledTimerWithTimeInterval(0.4, target: self, selector: #selector(MediaAudioPlayer.update), userInfo: nil, repeats: true)
}
// Play - Pause
if self.player?.playing == true {
self.player?.pause()
self.delegate?.playing = true
} else {
self.player?.play()
self.delegate?.playing = false
}
}
// Transform second to minute
func stringFromTimeInterval(interval: NSTimeInterval) -> NSString {
let ti = NSInteger(interval)
let seconds = ti % 60
let minutes = (ti / 60) % 60
return NSString(format: "%0.2d:%0.2d", minutes, seconds)
}
// MARK: Audio Session
private func setupAudioSession(category category: String) {
let session = AVAudioSession.sharedInstance()
do {
try session.setCategory(category)
try session.setActive(true)
} catch _ {}
}
// MARK: Stop
func stop() {
self.player?.stop()
self.player = nil // Deinit player
self.delegate?.playing = true
self.delegate = nil // Deinit delegate
self.timer?.invalidate(); self.timer = nil
self.lastURL = nil
}
// MARK: Playing
internal func playing() -> Bool {
if player != nil {
return player?.rate == 1.0 ? true : false
}
return false
}
// MARK: Seek
func seekToPosition(position position: Float) {
if let duration = self.player?.duration {
player?.currentTime = Double(position) * duration
self.delegate?.currentTimeAudio = stringFromTimeInterval((player?.currentTime)!) as String
}
}
func update() {
if sliderTouched == false {
if let currentTime = self.player?.currentTime, duration = player?.duration {
let time = Float(currentTime) / Float(duration)
self.delegate?.sliderPosition = time
self.delegate?.currentTimeAudio = stringFromTimeInterval((player?.currentTime)!) as String
}
}
}
// MARK: Delegate
var counter = 0
func audioPlayerDidFinishPlaying(player: AVAudioPlayer, successfully flag: Bool) {
print("Called")
self.lastURL = nil
self.delegate?.playing = true
/**
if flag == true {
nextSong(true)
}*/
/**
if ((counter + 1) == tracks.count) {
counter = 0
self.delegate?.playing = false
nextSong(false)
} else {
self.delegate?.playing = true
nextSong(true)
}
*/
}
}
Thank you!!

How to use presentViewController in a custom class?

I just update my code, but the alertWindow won't show up.
I add break point in Xcode, it shows that the viewDelegate is nil.
All delegates are nil.
This is my code:
class LoginViewController:UIViewController,AlertDelegate
{
override func viewDidLoad() {
super.viewDidLoad()
let BackGroundImage:UIImageView = UIImageView(frame: CGRectMake(0, 0, self.view.frame.width , self.view.frame.height))
let image: UIImage = UIImage(named: "backgroundLogin.jpg")!
BackGroundImage.image = image
self.view.addSubview(BackGroundImage)
//self.view.backgroundColor = UIColor(patternImage: UIImage(named: "backgroundLogin.jpg")!)
username.text = "User name"
password.text = "Password"
usernameWarning.text = ""
passwordWarning.text = ""
self.view.bringSubviewToFront(username)
self.view.bringSubviewToFront(password)
self.view.bringSubviewToFront(usernameText)
self.view.bringSubviewToFront(passwordText)
self.view.bringSubviewToFront(LoginButton)
self.view.bringSubviewToFront(RegisterButton)
self.view.bringSubviewToFront(usernameWarning)
self.view.bringSubviewToFront(passwordWarning)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
switch segue.identifier
{
case .Some("RegisterSegue"):
let registerViewController = segue.destinationViewController as! RegisterViewController
if let temp_register_username = usernameText!.text
{
registerViewController.register_name = temp_register_username
if let temp_register_pass = passwordText!.text
{
registerViewController.register_password = temp_register_pass
}
}
case .Some("loginSegue"):
let loginViewController = segue.destinationViewController as! FunctionsViewController
loginViewController.client = client
default:
super.prepareForSegue(segue, sender: sender)
}
}
override func shouldPerformSegueWithIdentifier(identifier: String, sender: AnyObject?) -> Bool {
if identifier == "loginSegue"
{
if usernameText.text != ""
{
if passwordText.text != ""
{
let encrypt = encryptMsg(send: passwordText.text!)
let encrypt_pass = encrypt.encryptSendMsg()
let sendMsg = AppConfig.AddHead("login", body: usernameText.text!+"|"+encrypt_pass)
let (_,_) = client.connect(timeout: 1)
let (success,_) = client.send(str: sendMsg)
if success
{
let data = client.read(1024*10)
if let d = data
{
if let str = String(bytes: d, encoding: NSUTF8StringEncoding)
{
if str[0...2] == AppConfig.TransmissionAgreementConfiguration["successLogin"]
{
AppConfig.StoreUserID(str)
let defaults = NSUserDefaults()
defaults.setObject(usernameText.text!, forKey: "userName")
let acceptThread = AcceptThread()
acceptThread.start()
return true
}
else if str[0...2] == AppConfig.TransmissionAgreementConfiguration["errLoginUsernameNotExist"]
{
usernameWarning.text = "User name doesn't exist"
usernameWarning.reloadInputViews()
passwordWarning.text = ""
passwordWarning.reloadInputViews()
return false
}
else if str[0...2] == AppConfig.TransmissionAgreementConfiguration["errLoginUsernameAlreadyOnline"]
{
usernameWarning.text = "User account already be online"
usernameWarning.reloadInputViews()
passwordWarning.text = ""
passwordWarning.reloadInputViews()
return false
}
else if str[0...2] == AppConfig.TransmissionAgreementConfiguration["errLoginPassword"]
{
usernameWarning.text = ""
usernameWarning.reloadInputViews()
passwordWarning.text = "Password Incorrect"
passwordWarning.reloadInputViews()
return false
}
}
}
}
return false
}
else
{
usernameWarning.text = ""
usernameWarning.reloadInputViews()
passwordWarning.text = "password cannot be empty"
passwordWarning.reloadInputViews()
return false
}
}
else
{
usernameWarning.text = "username cannot be empty"
usernameWarning.reloadInputViews()
return false
}
}
else
{
return true
}
}
func presentWindow(title:String,msg:String)
{
let alertController = UIAlertController(title: "\(title):", message: "\(msg)", preferredStyle: UIAlertControllerStyle.Alert)
alertController.addTextFieldWithConfigurationHandler{
(textField: UITextField!) -> Void in
textField.placeholder = "Message"
}
let cancelAction = UIAlertAction(title: "Ignore", style: UIAlertActionStyle.Cancel, handler: nil)
let okAction = UIAlertAction(title: "Reply", style: UIAlertActionStyle.Default,
handler: {
action in
let reply_msg = alertController.textFields!.first! as UITextField
print("I replies \(reply_msg)")
})
alertController.addAction(cancelAction)
alertController.addAction(okAction)
self.presentViewController(alertController, animated: true, completion: nil)
}
#IBAction func logoutUnwindSegue(segue: UIStoryboardSegue) {
// Intentionally left blank
}
var client:TCPClient = TCPClient(addr:"localhost",port:8889)
var AppConfig=TransmissionAgreement(first:"test")
#IBOutlet weak var usernameWarning: UILabel!
#IBOutlet weak var passwordWarning: UILabel!
#IBOutlet weak var username: UILabel!
#IBOutlet weak var password: UILabel!
#IBOutlet weak var usernameText: UITextField!
#IBOutlet weak var passwordText: UITextField!
#IBOutlet weak var LoginButton: UIButton!
#IBOutlet weak var RegisterButton: UIButton!
}
class AcceptThread: NSThread {
override func main() {
let server:TCPServer = TCPServer(addr:"127.0.0.1",port: 7000)
let (success,_) = server.listen()
if success
{
while !cancelled
{
if let my_client = server.accept()
{
let clientReadThread = ClientReadThread(client: my_client)
clientReadThread.start()
clientThreads.append(clientReadThread)
}
}
for clientThread in clientThreads {
clientThread.cancel()
}
}
}
var clientThreads = Array<ClientReadThread>()
var AppConfig=TransmissionAgreement(first:"test")
}
#objc protocol AlertDelegate: class {
func presentWindow(title:String,msg:String)
}
#objc protocol ClientReadThreadDelegate: class {
func clientReadThread(clientReadThread: ClientReadThread, didReceiveMessage message: String)
}
class ClientReadThread:NSThread{
init(client: TCPClient) {
self.client = client
super.init()
}
override func main() {
while !cancelled, let readValue = client.read(1024*10) {
if let message = String(bytes: readValue, encoding: NSUTF8StringEncoding) {
let head = message[0...2]
// print("head is \(head)")
if head! == AppConfig.TransmissionAgreementConfiguration["add"]
{
let defaults = NSUserDefaults()
let myname = defaults.stringForKey("userName")
//store data
let context = CoreDataService.sharedCoreDataService.mainQueueContext
let friend = NSEntityDescription.insertNewObjectForNamedEntity(Friends.self, inManagedObjectContext: context)
friend.name = message.substringFromIndex(3)
try! context.save()
let sendMsg = AppConfig.AddClientHead("agreeAdd", body:myname)
let (_,_) = client.send(str:sendMsg)
dispatch_async(dispatch_get_main_queue(), { () -> Void in
self.delegate?.clientReadThread(self, didReceiveMessage: message)
})
}
else if head! == AppConfig.TransmissionAgreementConfiguration["chat"]
{
let search = message.substringFromIndex(3)
let resultController = try? catFriend.sharedCatFriendsService.catBlack(search)
try! resultController!.performFetch()
let flag = resultController?.sections?.count
if flag <= 1//friend
{
dispatch_async(dispatch_get_main_queue(), { () -> Void in
let client_info = message.split("|")
let client_name = client_info[1]
//self.alertDelegate?.presentWindow(client_name, msg: client_info[2])
self.viewDelegate?.presentWindow(client_name, msg: client_info[2])
})
}
else//black, not show the meg
{
//do nothing
}
}
}
}
}
var AppConfig=TransmissionAgreement(first:"test")
let client: TCPClient
var viewDelegate:LoginViewController?
var delegate: ClientReadThreadDelegate?
var alertDelegate: AlertDelegate?
private var resultController: NSFetchedResultsController?
}
presentViewContoller is a method on UIViewController so you'll need an instance of a view controller to be able to present your alert view.
The way this would normally be done is to have the view controller you have start the ClientReadThread implement the AlertDelegate protocol. There's no reason for ClientReadThread to implement AlertDelegate itself. Would it ever be it's own delegate?
Also you delegate's should be marked weak or else you'll end up with a retain cycle.
class MyViewController : UIViewController, AlertDelegate {
private var clientReadThread: ClientReadThread?
override viewDidLoad() {
super.viewDidLoad();
clientReadThread = ClientReadThread(someTcpClient)
clientReadThread.viewDelegate = self
}
func presentWindow(title:String,msg:String) {
// Your code goes here.
}
}
Your other option would be to pass an instance of a UIViewController into your ClientReadThread and use that to present the alert view. Although that's not the way I would go. the ClientReadThread shouldn't need to know how it's alerts are handled, that should be delegated to another class.