Issues with UserDefaults.standard.value(forKey: "barcodeId") as! String - wkwebview

Can anyone tell me why the copied data from user defaults is not passing the correct value? Below is my code, the weird part about all of this is outside of the app, when pasting on to notes or safari on the device. It does indeed past the correct data. NOTE: I've removed the test url
let testURL = ""
// let barcodeData = UserDefaults.standard.value(forKey: "barcodeId") as! String
var barcodeData = UserDefaults.standard.value(forKey: "barcodeId") as! String
override func viewDidLoad() {
super.viewDidLoad()
}
#IBOutlet weak var webView: WKWebView!
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
webView.navigationDelegate = self
load(urlString: testURL)
}
// MARK: Private function
func load(urlString string: String) {
let url = URL(string: string)
let request = URLRequest(url: url!)
webView.load(request)
}
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
webView.evaluateJavaScript("document.getElementById('RCPT_BARCODE').value = \(barcodeData)") {(result, error) in
guard error == nil else {
print(error!)
return
}
print(String(describing: result))
}
}
}

Related

UIPickerView with Core Data Swift4

I am trying to re-use a code from swift 7.3. I feel I am very close.
When I try the code on the simulator, the picker view it is empty, but when I try to use it I have only one data show up.
I also try to adapt and other code to load data from core data to it, didn't work.
Any Idea?
Thank you
import CoreData
class ViewController: UIViewController, UIPickerViewDelegate, UIImagePickerControllerDelegate {
#IBOutlet weak var TextField: UITextField!
#IBOutlet weak var stylePicker: UIPickerView!
var styleData = [PilotBase]()
override func viewDidLoad() {
super.viewDidLoad()
let appDelegate = UIApplication.shared.delegate as! AppDelegate
let context = appDelegate.persistentContainer.viewContext
let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "PilotBase")
do {
styleData = try context.fetch(fetchRequest) as! [PilotBase]
} catch let err as NSError {
print(err.debugDescription)
}
let request = NSFetchRequest<NSFetchRequestResult>(entityName: "PilotBase")
request.returnsObjectsAsFaults = false
do{
let result = try context.fetch(request)
for data in result as! [NSManagedObject]{
print(data.value(forKey: "name") as! String)
}
}catch{
print("Failed")
}
}
func numberOfComponentsInPickerView(pickerView: UIPickerView) -> Int {
return 1
}
func pickerView(pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
if component == 0 {
return styleData.count
} else {
return 0
}
}
func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
if component == 0 {
return styleData[row].name
} else {
return nil
}
}
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
print(styleData[row])
stylePicker.selectRow(row, inComponent: 0, animated: true)
TextField.text = styleData[row].name
}
}
Below the code to add data to Core Data.
#IBAction func Save(_ sender: Any) {
let appDelegate = UIApplication.shared.delegate as! AppDelegate
let context = appDelegate.persistentContainer.viewContext
let entity = NSEntityDescription.entity(forEntityName: "PilotBase", in: context)
let newUser = NSManagedObject(entity: entity!, insertInto: context)
newUser.setValue(TextField.text!, forKey: "name")
do{
try context.save()
}catch{
print("failed saving")
}
}

logically false fetch request

I am doing a fetch request with a predicate mentioned in the block quote below, but I seem to get "logically false fetch request". What does this message mean and what step should I take to find the problem and resolve it?
annotation: logically false fetch request (entity: Country; predicate: ("alpha3Code" == "KOR"); sortDescriptors: ((null)); type: NSManagedObjectResultType; ) short circuits.
Here is the code that I get the error from
let record = Currency.fetch(id: currency)[0] as! Currency
where Currency class is as follows. "fetch" is implemented in NSManagedObjectProtocol trait
public class Currency: NSManagedObject, NSManagedObjectProtocol, XMLImporterDelegate {
private static let attributes = ["name", "currency", "decimalUnit", "isUsed"]
private static let xmlRecordTag = "CcyNtry"
private static let xmlAttributeTags = ["CcyNm": attributes[0],
"Ccy": attributes[1],
"CcyMnrUnts": attributes[2]]
static func setValue(managedObject: NSManagedObjectProtocol, object: Dictionary<String, Any>) {
let currency = managedObject as! Currency
currency.name = getString(from: object, withKeyValue: attributes[0])
currency.currency = getString(from: object, withKeyValue: attributes[1])
currency.decimalUnit = getInt16(from: object, withKeyValue: attributes[2])
currency.isUsed = getBool(from: object, withKeyValue: attributes[3])
return
}
static func getPredicates(forID id: Dictionary<String, Any>) -> [NSPredicate] {
var predicates: [NSPredicate] = []
predicates.append(NSPredicate.init(format: "%# = %#", attributes[1], getString(from: id, withKeyValue: attributes[1])))
return predicates
}
func isEqual(object: NSManagedObjectProtocol) -> Bool {
if let object = object as? Currency {
if object.currency == self.currency { return false }
return true
} else {
return false
}
}
static func recordTag() -> String {
return xmlRecordTag
}
static func attribute(byTag tag: String) -> String? {
return xmlAttributeTags[tag]
}
static func getUsed() -> [Any]?{
var predicates: [NSPredicate] = []
predicates.append(NSPredicate.init(format: "%# = %#", attributes[3], NSNumber(booleanLiteral: false)))
return fetch(predicates: predicates)
}
}
NSManagedObjectProtocol has following trait
extension NSManagedObjectProtocol {
public static func add(from objectValue: Dictionary<String, Any>) -> NSManagedObjectProtocol? {
let exists = fetch(id: objectValue)
if exists.count > 0 {
NSLog("Object already exists in CoreData : %#", objectValue.description)
return nil
} else {
return newObject(object: objectValue)
}
}
public static func addOrChange(from object: Dictionary<String, Any>) -> NSManagedObjectProtocol {
let exists = fetch(id: object)
if exists.count > 0 {
// TODO: confirm if data needs to be changed rather than delete and insert
}
delete(id: object)
return add(from: object)!
}
public static func getString(from object: Dictionary<String, Any>, withKeyValue key: String) -> String {
return object[key] as! String
}
public static func getInt16(from object: Dictionary<String, Any>, withKeyValue key: String) -> Int16 {
if let stringValue = object[key] as? String {
if let intValue = Int(stringValue) {
return Int16(intValue)
} else {
return 0
}
} else if let intValue = object[key] as? Int {
return Int16(intValue)
} else {
return 0
}
}
public static func getBool(from object: Dictionary<String, Any>, withKeyValue key: String) -> Bool {
if let boolValue = object[key] as? Bool {
return boolValue
} else {
return false
}
}
public static func fetch(predicates: [NSPredicate] = [], sortDescriptors: [NSSortDescriptor] = []) -> [Any] {
let request = Self.request(predicates: predicates)
do {
return try CoreDataHelper.getCoreDataHelper().context.fetch(request)
} catch {
return []
}
}
public static func fetch(id: Dictionary<String, Any>) -> [Any] {
return Self.fetch(predicates: Self.getPredicates(forID: id))
}
public static func delete(predicates: [NSPredicate] = []) {
let context = CoreDataHelper.getContext()
let fetchRequest = request(predicates: predicates)
let deleteRequest = NSBatchDeleteRequest(fetchRequest: fetchRequest)
do {
try context.execute(deleteRequest)
CoreDataHelper.getCoreDataHelper().saveContext()
} catch {
NSLog("Delete request failed")
return
}
}
public static func delete(id: Dictionary<String, Any>) {
delete(predicates: getPredicates(forID: id))
}
// MARK: - Private API
private static func newObject(object: Dictionary<String, Any>) -> NSManagedObjectProtocol {
let entityName = String(describing: self)
let context = CoreDataHelper.getContext()
let managedObject = NSEntityDescription.insertNewObject(forEntityName: entityName, into: context) as! NSManagedObjectProtocol
setValue(managedObject: managedObject, object: object)
CoreDataHelper.getCoreDataHelper().saveContext()
return managedObject
}
private static func request(predicates: [NSPredicate] = [], sortDescriptors: [NSSortDescriptor] = []) -> NSFetchRequest<NSFetchRequestResult> {
// Prepare a request
let entityName = String(describing: self)
let classObject: AnyClass! = NSClassFromString(entityName)
let objectType: NSManagedObject.Type = classObject as! NSManagedObject.Type!
let request: NSFetchRequest<NSFetchRequestResult> = objectType.fetchRequest()
// Add predicates
if predicates.count > 0 {
request.predicate = NSCompoundPredicate.init(andPredicateWithSubpredicates: predicates)
}
// Add sortDescriptors
if sortDescriptors.count > 0 {
request.sortDescriptors = sortDescriptors
}
return request
}
}
Finally this is how the CoreDataHelper looks like.
class CoreDataHelper: NSObject {
var context: NSManagedObjectContext!
var model: NSManagedObjectModel!
var coordinator: NSPersistentStoreCoordinator!
var store: NSPersistentStore!
let storeFilename = "Accounting.sqlite"
func setupCoreData() {
self.loadStore()
}
func saveContext() {
if (self.context.hasChanges) {
do {
try context.save()
} catch {
}
}
}
func applicationDocumentDictionary() -> String {
let directory = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).last!
NSLog("SQLite Directory : %#", directory)
return directory
}
func applicationStoresDirectory() -> URL {
let storesDirectory = URL.init(fileURLWithPath: self.applicationDocumentDictionary()).appendingPathComponent("Stores")
let fileManager = FileManager.default
if (!fileManager.fileExists(atPath: storesDirectory.path)) {
do {
try fileManager.createDirectory(at: storesDirectory,
withIntermediateDirectories: true,
attributes: nil)
} catch {
}
}
return storesDirectory
}
func storesURL() -> URL {
return self.applicationStoresDirectory().appendingPathComponent(storeFilename)
}
override init() {
super.init()
model = NSManagedObjectModel.mergedModel(from: nil)
coordinator = NSPersistentStoreCoordinator(managedObjectModel: model)
context = NSManagedObjectContext(concurrencyType: .mainQueueConcurrencyType)
context.persistentStoreCoordinator = coordinator
}
func loadStore() {
if (store != nil) {
return
} else {
do {
try store = coordinator.addPersistentStore(ofType: NSSQLiteStoreType,
configurationName: nil,
at: self.storesURL(),
options: nil)
} catch {
}
}
}
static func getCoreDataHelper() -> CoreDataHelper {
let appDelegate = UIApplication.shared.delegate as! AppDelegate
return appDelegate.coreDataHelper
}
static func getContext() -> NSManagedObjectContext {
return getCoreDataHelper().context
}
}
Just to let you know that Country class has alpha3Code.
extension Country {
#nonobjc public class func fetchRequest() -> NSFetchRequest<Country> {
return NSFetchRequest<Country>(entityName: "Country");
}
#NSManaged public var englishName: String?
#NSManaged public var frenchName: String?
#NSManaged public var alpha2Code: String?
#NSManaged public var alpha3Code: String?
#NSManaged public var countryNumber: Int16
}
Use the recommended format specifier %K for a key(path) rather than %# as described in the Predicate Documentation
predicates.append(NSPredicate.init(format: "%K = %#", attributes[1], getString(from: id, withKeyValue: attributes[1])))

How to write into the CoreData entity at the same index in different view controller (also swift files)

I have created core data using 'NSFetchedResultController' and 'managedObjectContext' in a table view. But in the later view controller, after gathering accelerometer data and conduct calculation, I will get some results that I also want to store in the same row index with the core data I created before.
How can I achieve this? If I create managedObjectContext again, it will create another 'row' of core data in this table.
The code in tableViewController:
'
let managedObjectContext = (UIApplication.sharedApplication().delegate as AppDelegate).managedObjectContext
var fetchedResultController: NSFetchedResultsController = NSFetchedResultsController()
override func viewDidLoad() {
super.viewDidLoad()
fetchedResultController = getFetchedResultController()
fetchedResultController.delegate = self
fetchedResultController.performFetch(nil)
}
func getFetchedResultController() -> NSFetchedResultsController {
fetchedResultController = NSFetchedResultsController(fetchRequest: trialFetchRequest(), managedObjectContext: managedObjectContext!, sectionNameKeyPath: nil, cacheName: nil)
return fetchedResultController
}
func trialFetchRequest() -> NSFetchRequest {
let fetchRequest = NSFetchRequest(entityName: "Trials")
fetchRequest.sortDescriptors = [NSSortDescriptor(key: "date", ascending: true)]
return fetchRequest
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
let numberOfSections = fetchedResultController.sections?.count
return numberOfSections!
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
let numberOfRowsInSection = fetchedResultController.sections?[section].numberOfObjects
return numberOfRowsInSection!
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as UITableViewCell
let trial = fetchedResultController.objectAtIndexPath(indexPath) as Trials
cell.textLabel?.text = trial.trialName
cell.detailTextLabel?.text = trial.date?.description
return cell
}
override func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
let managedObject:NSManagedObject = fetchedResultController.objectAtIndexPath(indexPath) as NSManagedObject
managedObjectContext?.deleteObject(managedObject)
managedObjectContext?.save(nil)
}
func controllerDidChangeContent(controller: NSFetchedResultsController!) {
tableView.reloadData()
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
if segue.identifier == "showTrial" {
let indexPath = tableView.indexPathForSelectedRow()
let trial:Trials = fetchedResultController.objectAtIndexPath(indexPath!) as Trials
let trialController:TrialDetailViewController = segue.destinationViewController as TrialDetailViewController
trialController.trial = trial
}
}
'
The code in the createTrial Controller:
' let managedObjectContext = (UIApplication.sharedApplication().delegate as AppDelegate).managedObjectContext
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
if segue.identifier == "createTrial" {
if theTrialName.text != "" {
createTrial()
} else {
let alertView = UIAlertController(title: "", message: "Trial name couldn't be empty", preferredStyle: .Alert)
alertView.addAction(UIAlertAction(title: "OK", style: .Cancel, handler: nil))
presentViewController(alertView, animated: true, completion: nil)
}
}
}
func createTrial() {
let entityDescripition = NSEntityDescription.entityForName("Trials", inManagedObjectContext: managedObjectContext!)
let trial = Trials(entity: entityDescripition!, insertIntoManagedObjectContext: managedObjectContext)
trial.trialName = theTrialName.text
trial.location = theLocation.text
trial.notes = theNotes.text
if theArm.on {
trial.arm = 1
} else {
trial.arm = 0
}
managedObjectContext?.save(nil)
}
'
ps. the view controller I want to get data from is not this following segue, it is around 3 view afterwards. And I have created a string to store the data I need in that view.
I solved the problem by creating the object in the tableViewControllerand use segue twice to transmit it to secondViewControllerand thirdViewController. So it will be at the same index for the whole time. And I can change the content of the core data at both the following view controllers.

SWIFT: Why is "NSURL(string:" returning with Nil, even though it's a valid url in a browser?

The first two example links are working the third one returns NIL.
Why is NSUrl returning nil for such string, even though it's a valid url in a browser?
Am I supposed to process the string more?
Here is my code:
import UIKit
import Foundation
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate, NSXMLParserDelegate {
var myFeed : NSArray = []
var url : NSURL!
var feedURL : NSURL!
var selectedFeedURL = String()
#IBOutlet var tableFeeds: UITableView!
#IBOutlet var webView: UIWebView!
override func viewDidLoad() {
super.viewDidLoad()
// Set feed url.
//url = NSURL(string: "http://www.skysports.com/rss/0,20514,11661,00.xml")! //This seems to work
//url = NSURL(string: "http://www.formula1.com/rss/news/latest.rss")! //This seems to work
url = NSURL(string: "http://www.multirotorusa.com/feed/")!
loadRss(url);
}
func loadRss(data: NSURL) {
var myParser : XmlParserManager = XmlParserManager.alloc().initWithURL(data) as XmlParserManager
myFeed = myParser.feeds
tableFeeds.reloadData()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return myFeed.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as UITableViewCell
var dict : NSDictionary! = myFeed.objectAtIndex(indexPath.row) as NSDictionary
cell.textLabel?.text = myFeed.objectAtIndex(indexPath.row).objectForKey("title") as? String
cell.detailTextLabel?.text = myFeed.objectAtIndex(indexPath.row).objectForKey("description") as? String
return cell
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
var indexPath: NSIndexPath = self.tableFeeds.indexPathForSelectedRow()!
var selectedFeedURL = myFeed.objectAtIndex(indexPath.row).objectForKey("link") as String
selectedFeedURL = selectedFeedURL.stringByReplacingOccurrencesOfString(" ", withString:"")
selectedFeedURL = selectedFeedURL.stringByReplacingOccurrencesOfString("\n", withString:"")
// feedURL = NSURL(fileURLWithPath: selectedFeedURL) //This returns with: URL + /%09%09 -- file:///
feedURL = NSURL(string: selectedFeedURL) //This returns with NIL
println("Selected Feed URL: \(selectedFeedURL)")
println("Feed URL: \(feedURL)")
if feedURL != nil {
let request : NSURLRequest = NSURLRequest(URL: feedURL!)
webView.loadRequest(request)
println("Feed URL: \(feedURL)") //Doesn't make it here
}
}
}
Any suggestions?
You should URL-encode the URL like this:
selectedFeedUrl = selectedFeedUrl.stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding)
In iOs 9:
myString = myString.stringByAddingPercentEncodingWithAllowedCharacters(NSCharacterSet.URLQueryAllowedCharacterSet())!
Hope it helps
For swift3 you can do like this
let url = URL(string:url.addingPercentEncoding(withAllowedCharacters: NSCharacterSet.urlQueryAllowed)!)!
Thank you guys for your help.
I added these two lines to my code and it works now:
selectedFeedURL = selectedFeedURL.stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding)!
selectedFeedURL = selectedFeedURL.stringByReplacingOccurrencesOfString("%09%09", withString:"")

Recording audio in Swift

Does anyone know where I can find info on how to record audio in a Swift application? I've been looking at some of the audio playback examples but I can't seem to be able to find anything on implementing the audio recording. Thanks
In Swift 3
Add framework AVFoundation
**In info.plist add key value
Key = Privacy - Microphone Usage Description and Value = For using
microphone
(the apps will crash if you don't provide the value - description why you are asking for the permission)**
Import AVFoundation & AVAudioRecorderDelegate, AVAudioPlayerDelegate
import AVFoundation
class RecordVC: UIViewController , AVAudioRecorderDelegate, AVAudioPlayerDelegate
Create button for record audio & play audio , and label for display recording timing & give outlets and action as start_recording , play_recording & declare some variables which we will use later
#IBOutlet var recordingTimeLabel: UILabel!
#IBOutlet var record_btn_ref: UIButton!
#IBOutlet var play_btn_ref: UIButton!
var audioRecorder: AVAudioRecorder!
var audioPlayer : AVAudioPlayer!
var meterTimer:Timer!
var isAudioRecordingGranted: Bool!
var isRecording = false
var isPlaying = false
In viewDidLoad check record permission
override func viewDidLoad() {
super.viewDidLoad()
check_record_permission()
}
func check_record_permission()
{
switch AVAudioSession.sharedInstance().recordPermission() {
case AVAudioSessionRecordPermission.granted:
isAudioRecordingGranted = true
break
case AVAudioSessionRecordPermission.denied:
isAudioRecordingGranted = false
break
case AVAudioSessionRecordPermission.undetermined:
AVAudioSession.sharedInstance().requestRecordPermission({ (allowed) in
if allowed {
self.isAudioRecordingGranted = true
} else {
self.isAudioRecordingGranted = false
}
})
break
default:
break
}
}
generate path where you want to save that recording as myRecording.m4a
func getDocumentsDirectory() -> URL
{
let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
let documentsDirectory = paths[0]
return documentsDirectory
}
func getFileUrl() -> URL
{
let filename = "myRecording.m4a"
let filePath = getDocumentsDirectory().appendingPathComponent(filename)
return filePath
}
Setup the recorder
func setup_recorder()
{
if isAudioRecordingGranted
{
let session = AVAudioSession.sharedInstance()
do
{
try session.setCategory(AVAudioSessionCategoryPlayAndRecord, with: .defaultToSpeaker)
try session.setActive(true)
let settings = [
AVFormatIDKey: Int(kAudioFormatMPEG4AAC),
AVSampleRateKey: 44100,
AVNumberOfChannelsKey: 2,
AVEncoderAudioQualityKey:AVAudioQuality.high.rawValue
]
audioRecorder = try AVAudioRecorder(url: getFileUrl(), settings: settings)
audioRecorder.delegate = self
audioRecorder.isMeteringEnabled = true
audioRecorder.prepareToRecord()
}
catch let error {
display_alert(msg_title: "Error", msg_desc: error.localizedDescription, action_title: "OK")
}
}
else
{
display_alert(msg_title: "Error", msg_desc: "Don't have access to use your microphone.", action_title: "OK")
}
}
Start recording when button start_recording press & display seconds using updateAudioMeter, & if recording is start then finish the recording
#IBAction func start_recording(_ sender: UIButton)
{
if(isRecording)
{
finishAudioRecording(success: true)
record_btn_ref.setTitle("Record", for: .normal)
play_btn_ref.isEnabled = true
isRecording = false
}
else
{
setup_recorder()
audioRecorder.record()
meterTimer = Timer.scheduledTimer(timeInterval: 0.1, target:self, selector:#selector(self.updateAudioMeter(timer:)), userInfo:nil, repeats:true)
record_btn_ref.setTitle("Stop", for: .normal)
play_btn_ref.isEnabled = false
isRecording = true
}
}
func updateAudioMeter(timer: Timer)
{
if audioRecorder.isRecording
{
let hr = Int((audioRecorder.currentTime / 60) / 60)
let min = Int(audioRecorder.currentTime / 60)
let sec = Int(audioRecorder.currentTime.truncatingRemainder(dividingBy: 60))
let totalTimeString = String(format: "%02d:%02d:%02d", hr, min, sec)
recordingTimeLabel.text = totalTimeString
audioRecorder.updateMeters()
}
}
func finishAudioRecording(success: Bool)
{
if success
{
audioRecorder.stop()
audioRecorder = nil
meterTimer.invalidate()
print("recorded successfully.")
}
else
{
display_alert(msg_title: "Error", msg_desc: "Recording failed.", action_title: "OK")
}
}
Play the recording
func prepare_play()
{
do
{
audioPlayer = try AVAudioPlayer(contentsOf: getFileUrl())
audioPlayer.delegate = self
audioPlayer.prepareToPlay()
}
catch{
print("Error")
}
}
#IBAction func play_recording(_ sender: Any)
{
if(isPlaying)
{
audioPlayer.stop()
record_btn_ref.isEnabled = true
play_btn_ref.setTitle("Play", for: .normal)
isPlaying = false
}
else
{
if FileManager.default.fileExists(atPath: getFileUrl().path)
{
record_btn_ref.isEnabled = false
play_btn_ref.setTitle("pause", for: .normal)
prepare_play()
audioPlayer.play()
isPlaying = true
}
else
{
display_alert(msg_title: "Error", msg_desc: "Audio file is missing.", action_title: "OK")
}
}
}
When recording is finish enable the play button & when play is finish enable the record button
func audioRecorderDidFinishRecording(_ recorder: AVAudioRecorder, successfully flag: Bool)
{
if !flag
{
finishAudioRecording(success: false)
}
play_btn_ref.isEnabled = true
}
func audioPlayerDidFinishPlaying(_ player: AVAudioPlayer, successfully flag: Bool)
{
record_btn_ref.isEnabled = true
}
Generalize function for display alert
func display_alert(msg_title : String , msg_desc : String ,action_title : String)
{
let ac = UIAlertController(title: msg_title, message: msg_desc, preferredStyle: .alert)
ac.addAction(UIAlertAction(title: action_title, style: .default)
{
(result : UIAlertAction) -> Void in
_ = self.navigationController?.popViewController(animated: true)
})
present(ac, animated: true)
}
Here is code.You can record easily.Write this code on IBAction.It will save the recording in Documents by name recordTest.caf
//declare instance variable
var audioRecorder:AVAudioRecorder!
func record(){
var audioSession:AVAudioSession = AVAudioSession.sharedInstance()
audioSession.setCategory(AVAudioSessionCategoryPlayAndRecord, error: nil)
audioSession.setActive(true, error: nil)
var documents: AnyObject = NSSearchPathForDirectoriesInDomains( NSSearchPathDirectory.DocumentDirectory, NSSearchPathDomainMask.UserDomainMask, true)[0]
var str = documents.stringByAppendingPathComponent("recordTest.caf")
var url = NSURL.fileURLWithPath(str as String)
var recordSettings = [AVFormatIDKey:kAudioFormatAppleIMA4,
AVSampleRateKey:44100.0,
AVNumberOfChannelsKey:2,AVEncoderBitRateKey:12800,
AVLinearPCMBitDepthKey:16,
AVEncoderAudioQualityKey:AVAudioQuality.Max.rawValue]
println("url : \(url)")
var error: NSError?
audioRecorder = AVAudioRecorder(URL:url, settings: recordSettings, error: &error)
if let e = error {
println(e.localizedDescription)
} else {
audioRecorder.record()
}
}
Swift2 version of #codester's answer.
func record() {
//init
let audioSession:AVAudioSession = AVAudioSession.sharedInstance()
//ask for permission
if (audioSession.respondsToSelector("requestRecordPermission:")) {
AVAudioSession.sharedInstance().requestRecordPermission({(granted: Bool)-> Void in
if granted {
print("granted")
//set category and activate recorder session
try! audioSession.setCategory(AVAudioSessionCategoryPlayAndRecord)
try! audioSession.setActive(true)
//get documnets directory
let documentsDirectory = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)[0]
let fullPath = documentsDirectory.stringByAppendingPathComponent("voiceRecording.caf")
let url = NSURL.fileURLWithPath(fullPath)
//create AnyObject of settings
let settings: [String : AnyObject] = [
AVFormatIDKey:Int(kAudioFormatAppleIMA4), //Int required in Swift2
AVSampleRateKey:44100.0,
AVNumberOfChannelsKey:2,
AVEncoderBitRateKey:12800,
AVLinearPCMBitDepthKey:16,
AVEncoderAudioQualityKey:AVAudioQuality.Max.rawValue
]
//record
try! self.audioRecorder = AVAudioRecorder(URL: url, settings: settings)
} else{
print("not granted")
}
})
}
}
In addition to previous answers, I tried to make it work on Xcode 7.2 and I couldn't hear any sound after, neither when I sent the file via email. No warning or exception.
So I changed settings to the following and stored as an .m4a file.
let recordSettings = [AVSampleRateKey : NSNumber(float: Float(44100.0)),
AVFormatIDKey : NSNumber(int: Int32(kAudioFormatMPEG4AAC)),
AVNumberOfChannelsKey : NSNumber(int: 1),
AVEncoderAudioQualityKey : NSNumber(int: Int32(AVAudioQuality.Medium.rawValue))]
After that I could listen to sound.
For saving the file, I added this on viewDidLoad to initialise the recorder:
let audioSession = AVAudioSession.sharedInstance()
do {
try audioSession.setCategory(AVAudioSessionCategoryPlayAndRecord)
try audioRecorder = AVAudioRecorder(URL: self.directoryURL()!,
settings: recordSettings)
audioRecorder.prepareToRecord()
} catch {
}
And for creating the directory:
func directoryURL() -> NSURL? {
let fileManager = NSFileManager.defaultManager()
let urls = fileManager.URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)
let documentDirectory = urls[0] as NSURL
let soundURL = documentDirectory.URLByAppendingPathComponent("sound.m4a")
return soundURL
}
I also add the actions used to start recording, stop, and play after
#IBAction func doRecordAction(sender: AnyObject) {
if !audioRecorder.recording {
let audioSession = AVAudioSession.sharedInstance()
do {
try audioSession.setActive(true)
audioRecorder.record()
} catch {
}
}
}
#IBAction func doStopRecordingAction(sender: AnyObject) {
audioRecorder.stop()
let audioSession = AVAudioSession.sharedInstance()
do {
try audioSession.setActive(false)
} catch {
}
}
#IBAction func doPlayAction(sender: AnyObject) {
if (!audioRecorder.recording){
do {
try audioPlayer = AVAudioPlayer(contentsOfURL: audioRecorder.url)
audioPlayer.play()
} catch {
}
}
}
Here audio recorder with simple interface written on Swift 4.2 .
final class AudioRecorderImpl: NSObject {
private let session = AVAudioSession.sharedInstance()
private var player: AVAudioPlayer?
private var recorder: AVAudioRecorder?
private lazy var permissionGranted = false
private lazy var isRecording = false
private lazy var isPlaying = false
private var fileURL: URL?
private let settings = [
AVFormatIDKey: Int(kAudioFormatMPEG4AAC),
AVSampleRateKey: 44100,
AVNumberOfChannelsKey: 2,
AVEncoderAudioQualityKey:AVAudioQuality.high.rawValue
]
override init() {
fileURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first?.appendingPathComponent("note.m4a")
}
func record(to url: URL?) {
guard permissionGranted,
let url = url ?? fileURL else { return }
setupRecorder(url: url)
if isRecording {
stopRecording()
}
isRecording = true
recorder?.record()
}
func stopRecording() {
isRecording = false
recorder?.stop()
try? session.setActive(false)
}
func play(from url: URL?) {
guard let url = url ?? fileURL else { return }
setupPlayer(url: url)
if isRecording {
stopRecording()
}
if isPlaying {
stopPlaying()
}
if FileManager.default.fileExists(atPath: url.path) {
isPlaying = true
setupPlayer(url: url)
player?.play()
}
}
func stopPlaying() {
player?.stop()
}
func pause() {
player?.pause()
}
func resume() {
if player?.isPlaying == false {
player?.play()
}
}
func checkPermission(completion: ((Bool) -> Void)?) {
func assignAndInvokeCallback(_ granted: Bool) {
self.permissionGranted = granted
completion?(granted)
}
switch session.recordPermission {
case .granted:
assignAndInvokeCallback(true)
case .denied:
assignAndInvokeCallback(false)
case .undetermined:
session.requestRecordPermission(assignAndInvokeCallback)
}
}
}
extension AudioRecorderImpl: AVAudioRecorderDelegate, AVAudioPlayerDelegate {
}
private extension AudioRecorderImpl {
func setupRecorder(url: URL) {
guard
permissionGranted else { return }
try? session.setCategory(.playback, mode: .default)
try? session.setActive(true)
let settings = [
AVFormatIDKey: Int(kAudioFormatMPEG4AAC),
AVSampleRateKey: 44100,
AVNumberOfChannelsKey: 2,
AVEncoderAudioQualityKey: AVAudioQuality.high.rawValue
]
recorder = try? AVAudioRecorder(url: url, settings: settings)
recorder?.delegate = self
recorder?.isMeteringEnabled = true
recorder?.prepareToRecord()
}
func setupPlayer(url: URL) {
player = try? AVAudioPlayer(contentsOf: url)
player?.delegate = self
player?.prepareToPlay()
}
}
For Swift 5,
func setup_recorder()
{
if isAudioRecordingGranted
{
let session = AVAudioSession.sharedInstance()
do
{
try session.setCategory(.playAndRecord, mode: .default)
try session.setActive(true)
let settings = [
AVFormatIDKey: Int(kAudioFormatMPEG4AAC),
AVSampleRateKey: 44100,
AVNumberOfChannelsKey: 2,
AVEncoderAudioQualityKey:AVAudioQuality.high.rawValue
]
audioRecorder = try AVAudioRecorder(url: getFileUrl(), settings: settings)
audioRecorder.delegate = self
audioRecorder.isMeteringEnabled = true
audioRecorder.prepareToRecord()
}
catch let error {
display_alert(msg_title: "Error", msg_desc: error.localizedDescription, action_title: "OK")
}
}
else
{
display_alert(msg_title: "Error", msg_desc: "Don't have access to use your microphone.", action_title: "OK")
}
Code in Class file Using Swift 4
Class is AGAudioRecorder
Code is
class AudioRecordViewController: UIViewController {
#IBOutlet weak var recodeBtn: UIButton!
#IBOutlet weak var playBtn: UIButton!
var state: AGAudioRecorderState = .Ready
var recorder: AGAudioRecorder = AGAudioRecorder(withFileName: "TempFile")
override func viewDidLoad() {
super.viewDidLoad()
recodeBtn.setTitle("Recode", for: .normal)
playBtn.setTitle("Play", for: .normal)
recorder.delegate = self
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
#IBAction func recode(_ sender: UIButton) {
recorder.doRecord()
}
#IBAction func play(_ sender: UIButton) {
recorder.doPlay()
}
}
extension AudioRecordViewController: AGAudioRecorderDelegate {
func agAudioRecorder(_ recorder: AGAudioRecorder, withStates state: AGAudioRecorderState) {
switch state {
case .error(let e): debugPrint(e)
case .Failed(let s): debugPrint(s)
case .Finish:
recodeBtn.setTitle("Recode", for: .normal)
case .Recording:
recodeBtn.setTitle("Recoding Finished", for: .normal)
case .Pause:
playBtn.setTitle("Pause", for: .normal)
case .Play:
playBtn.setTitle("Play", for: .normal)
case .Ready:
recodeBtn.setTitle("Recode", for: .normal)
playBtn.setTitle("Play", for: .normal)
refreshBtn.setTitle("Refresh", for: .normal)
}
debugPrint(state)
}
func agAudioRecorder(_ recorder: AGAudioRecorder, currentTime timeInterval: TimeInterval, formattedString: String) {
debugPrint(formattedString)
}
}
Swift 3 Code Version: Complete Solution for Audio Recording!
import UIKit
import AVFoundation
class ViewController: UIViewController, AVAudioRecorderDelegate {
//Outlets
#IBOutlet weak var recordingTimeLabel: UILabel!
//Variables
var audioRecorder: AVAudioRecorder!
var meterTimer:Timer!
var isAudioRecordingGranted: Bool!
override func viewDidLoad() {
super.viewDidLoad()
switch AVAudioSession.sharedInstance().recordPermission() {
case AVAudioSessionRecordPermission.granted:
isAudioRecordingGranted = true
break
case AVAudioSessionRecordPermission.denied:
isAudioRecordingGranted = false
break
case AVAudioSessionRecordPermission.undetermined:
AVAudioSession.sharedInstance().requestRecordPermission() { [unowned self] allowed in
DispatchQueue.main.async {
if allowed {
self.isAudioRecordingGranted = true
} else {
self.isAudioRecordingGranted = false
}
}
}
break
default:
break
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
audioRecorder = nil
}
//MARK:- Audio recorder buttons action.
#IBAction func audioRecorderAction(_ sender: UIButton) {
if isAudioRecordingGranted {
//Create the session.
let session = AVAudioSession.sharedInstance()
do {
//Configure the session for recording and playback.
try session.setCategory(AVAudioSessionCategoryPlayAndRecord, with: .defaultToSpeaker)
try session.setActive(true)
//Set up a high-quality recording session.
let settings = [
AVFormatIDKey: Int(kAudioFormatMPEG4AAC),
AVSampleRateKey: 44100,
AVNumberOfChannelsKey: 2,
AVEncoderAudioQualityKey: AVAudioQuality.high.rawValue
]
//Create audio file name URL
let audioFilename = getDocumentsDirectory().appendingPathComponent("audioRecording.m4a")
//Create the audio recording, and assign ourselves as the delegate
audioRecorder = try AVAudioRecorder(url: audioFilename, settings: settings)
audioRecorder.delegate = self
audioRecorder.isMeteringEnabled = true
audioRecorder.record()
meterTimer = Timer.scheduledTimer(timeInterval: 0.1, target:self, selector:#selector(self.updateAudioMeter(timer:)), userInfo:nil, repeats:true)
}
catch let error {
print("Error for start audio recording: \(error.localizedDescription)")
}
}
}
#IBAction func stopAudioRecordingAction(_ sender: UIButton) {
finishAudioRecording(success: true)
}
func finishAudioRecording(success: Bool) {
audioRecorder.stop()
audioRecorder = nil
meterTimer.invalidate()
if success {
print("Recording finished successfully.")
} else {
print("Recording failed :(")
}
}
func updateAudioMeter(timer: Timer) {
if audioRecorder.isRecording {
let hr = Int((audioRecorder.currentTime / 60) / 60)
let min = Int(audioRecorder.currentTime / 60)
let sec = Int(audioRecorder.currentTime.truncatingRemainder(dividingBy: 60))
let totalTimeString = String(format: "%02d:%02d:%02d", hr, min, sec)
recordingTimeLabel.text = totalTimeString
audioRecorder.updateMeters()
}
}
func getDocumentsDirectory() -> URL {
let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
let documentsDirectory = paths[0]
return documentsDirectory
}
//MARK:- Audio recoder delegate methods
func audioRecorderDidFinishRecording(_ recorder: AVAudioRecorder, successfully flag: Bool) {
if !flag {
finishAudioRecording(success: false)
}
}
}
Simple 2022 syntax, record audio on iPhone.
Older answers don't work.
Needed ...
var mic: AVAudioRecorder?
var workingFile: URL {
return FileManager.default.temporaryDirectory.appendingPathComponent("temp.m4a")
}
And then
#IBAction public func tapTalkSend() {
switch AVCaptureDevice.authorizationStatus(for: .audio) {
case .authorized: _talkSend()
case .notDetermined:
AVCaptureDevice.requestAccess(for: .video) { [weak self] granted in
if granted { self?._talkSend() }
}
case .denied: return
case .restricted: return
#unknown default:
return
}
}
And then
public func _talkSend() {
if mic != nil && mic!.isRecording {
mic?.stop()
mic = nil
return
}
do {
try AVAudioSession.sharedInstance().setCategory(.playAndRecord, mode: .default)
try AVAudioSession.sharedInstance().setActive(true)
mic = try AVAudioRecorder(url: workingFile, settings: [:])
}
catch let error {
return print("mic drama \(error)")
}
mic!.delegate = self
mic!.record()
}
Add AVAudioRecorderDelegate on your vc. And:
func audioRecorderDidFinishRecording(_ recorder: AVAudioRecorder, successfully flag: Bool) {
_testPlay() ...
_sendFileSomewhere() ...
}
func audioRecorderEncodeErrorDidOccur(_ recorder: AVAudioRecorder, error: Error?) {
print("audioRecorderEncodeErrorDidOccur")
}
To test by playing it back:
var myPlayer: AVAudioPlayer!
func _testPlay() {
do {
myPlayer = try AVAudioPlayer(contentsOf: workingFile)
myPlayer.prepareToPlay()
myPlayer.play()
}
catch let error {
return print("play drama \(error)")
}
}
In your plist:
<key>NSCameraUsageDescription</key>
<string>For spoken messages.</string>
<key>NSMicrophoneUsageDescription</key>
<string>For spoken messages.</string>

Resources