I am trying to set the preferred input to my AVAudioEngine. I have the following code:
var iphoneInput: AVAudioSessionPortDescription = AVAudioSession.sharedInstance().availableInputs[0] as! AVAudioSessionPortDescription
var error: NSError?
session.setPreferredInput(inPort: iphoneInput, error: error)
but Xcode keeps giving me errors for the last line stating taht it cannot invoke setPreferredinput with an arguement list of type '(AVAudioSessionPortDescription, NSError?)'
I am assuming it wants a NSErrorPointer for the error but I do not know how to create one in swift. Is this my problem and if so how do I create one? thanks!
Add a & character before the variable to make it a pointer:
var myError: NSError?
session.setPreferredInput(iphoneInput, error: &myError)
if myError == nil {
// do stuff
}
Note: in Swift you don't have to use the method's first parameter's name.
for swift 3 does not work... you have to do (translated from ADC:
https://developer.apple.com/library/content/qa/qa1799/_index.html
)
private func setupSession(){
let session = AVAudioSession.sharedInstance()
// setup session:
do {
try session.setCategory(AVAudioSessionCategoryPlayAndRecord, with: .defaultToSpeaker)
try session.setActive(true)
}
catch _{
}
// https://developer.apple.com/library/content/qa/qa1799/_index.html
// let portDescr = AVAudioSessionPortDescription()
// headers:
// AVAudioSessionPortLineIn: String // Line level input on a dock connector
// AVAudioSessionPortBuiltInMic: String // Built-in microphone on an iOS device
// AVAudioSessionPortHeadsetMic: String // Microphone on a wired headset. Headset refers to an accessory that has headphone outputs paired with a microphone.
// You cannot set directly..
// portDescr.portType = AVAudioSessionPortLineIn
guard let availableInputs = session.availableInputs else {
return
}
var mic : AVAudioSessionPortDescription? = nil
for input in availableInputs {
if input.portType == AVAudioSessionPortBuiltInMic{
mic = input
}
}
guard mic != nil else{
return
}
do {
try session.setPreferredInput(mic)
}catch _ {
print("cannot set mic ")
}
}
Related
I'm trying to save player game data using GKSavedGame from GameKit, but it doesn't work, and I don't get any error. (Is the data not saving? Is the data not loading back?)
One of the problem is that GKSavedGame is not well documented (there are no examples like we can find for other things), so we don't really know how to implement it correctly (e.g. what are the best practices?)
I'm using a simple struct GameData: Codable to store the game data, that I encode using JSONEncoder/JSONDecoder. Here is my GameService class with the part that doesn't work:
class GameService {
// Shared instance
static let shared = GameService()
// Properties
private(set) var isGameLoaded = false
private(set) var gameData: GameData?
// Methods
func loadSavedGame(completionHandler: #escaping () -> Void) {
// Check game is not loaded yet
if isGameLoaded {
completionHandler()
return
}
// Get player
let localPlayer = GKLocalPlayer.local
if localPlayer.isAuthenticated {
localPlayer.fetchSavedGames { games, error in
// Iterate saved games
var game: GKSavedGame?
for currentGame in games ?? [] {
if game == nil || game?.modificationDate ?? Date() < currentGame.modificationDate ?? Date() {
game = currentGame
}
}
// If one found, load its data
if let game = game {
game.loadData { data, error in
if let data = data {
self.gameData = try? JSONDecoder().decode(GameData.self, from: data)
}
self.isGameLoaded = true
self.initGameData()
completionHandler()
}
} else {
self.isGameLoaded = true
self.initGameData()
completionHandler()
}
}
}
}
func saveGame() {
// Get player
let localPlayer = GKLocalPlayer.local
if localPlayer.isAuthenticated, let gameData = gameData, let data = try? JSONEncoder().encode(gameData) {
// Save its game data
localPlayer.saveGameData(data, withName: "data") { savedGame, error in
if let error = error {
print(error.localizedDescription)
}
}
}
}
func initGameData() {
// If game data is undefined, define it
if gameData == nil {
gameData = GameData()
}
}
func gameEnded(level: Level, score: Int64) {
// Here I edit my `gameData` object before saving the changes
// I known that this method is called because the data is up to date in the UI
// ...
saveGame()
}
}
Also, GameCenter is enabled in the app capabilities (and workout for other things like leaderboards)
After restarting the app, and calling loadSavedGame, the gameData property is not restored to its previous state.
What is wrong with this code?
Note: I tested it on both Simulator and on my own iPhone (real daily device where GameCenter and iCloud are working with other apps) and it never saves anything.
After enabling iCloud in Capabilities, iCloud Documents, and creating a container for the app, it now works. There is nothing in the documentation about this.
I have a button setup so that it saves a CK record based on a users choice from a different part of the UI. Once the function is called the CKRecord is saved in a variable. The next operation the code should take is unwrapping that variable and using it to edit and save the CK record. The Issue is the function I call first, loadChallengeRecord(), isn't the first operation made when the button is pressed. Instead the unwrapping function is run first which is causing the program to exit the unwrap function because the record is nil, and then the loadChallengeRecord() function is called late. Here is the example:
func loadChallengeRecord() {
if let unwrapped = existingChallengeToDetails {
recordID = CKRecord.ID(recordName: unwrapped, zoneID: zone)
publicDatabase.fetch(withRecordID: recordID!) { (record, error) in
if record != nil {
self.currentChallenge = record
} else {
print("error fetching challenge record from server")
}
}
}
}
#IBAction func btnVote(_ sender: Any) {
// load record and save it to var existingChallengeToDetails
loadChallengeRecord()
if let unwrapped = existingChallengeToDetails { }// edit and save record
else { // error }
What am i doing wrong? How can i fix this? Can I denote a priority for these functions to run?
Write your function with completion handler like this
func loadChallengeRecord(completion:#escaping ()->Void) {
if let unwrapped = existingChallengeToDetails {
recordID = CKRecord.ID(recordName: unwrapped, zoneID: zone)
publicDatabase.fetch(withRecordID: recordID!) { (record, error) in
defer { completion }
if record != nil {
self.currentChallenge = record
} else {
print("error fetching challenge record from server")
}
}
}
}
Use it like this ... when it returns completion you can do other stuff dependent on this
loadChallengeRecord {
// do your stuff here
}
The easiest solution is to do the things you have to do in the (asynchronous) completion handler
func loadChallengeRecord() {
guard let unwrapped = existingChallengeToDetails else { return }
recordID = CKRecord.ID(recordName: unwrapped, zoneID: zone)
publicDatabase.fetch(withRecordID: recordID!) { (record, error) in
if let record = record {
self.currentChallenge = record
// edit and save record
} else {
print("error fetching challenge record from server", error!)
}
}
}
#IBAction func btnVote(_ sender: Any) {
// load record and save it to var existingChallengeToDetails
loadChallengeRecord()
}
The other two answers worked for the specific case, and work for many causes, but they weren't exactly what I was looking for. I kept running to similar issues and after some research I finally found what I was looking for: Semaphores
Here is a basic explanation:
func doSomething() {
let semaphore = DispatchSemaphore(value: 0) // Setup the semaphore to value:0
var x = 1
var y = 2
if y != 0 {
var sum = x + y
semaphore.signal(). // Sends signal that code is complete
// the code can continue from where semaphore.wait() is located.
}
semaphore.wait() // Wait for semaphore.signal() to fire, then continue to return
return sum // only after semaphore.signal() fires will this code run
}
On the 3rd line in the function below I get the following error:
Unable to infer closure type in the current context
How do I fix this?
func fetchAllUsersImages() {
print("inside func")
self.ref.child("Posts").child(self.userID).child(self.postNum).observe(.childAdded, with: { snapshot in //error here
var images: [URL] = []
if let snapShotValue = snapshot.value as? [String: String] {
for (_, value) in snapShotValue {
if let imageURL = URL(string: value) {
print(imageURL, "image url here")
let imageAsData = try Data(contentsOf: imageURL)
let image = UIImage(data: imageAsData)
let ImageObject = Image()
ImageObject.image = image
self.arrayOfImgObj.append(ImageObject)
self.tableView.reloadData()
}
}
}
})
}
The reason why it is not inferring the closure type is because the try statement is not handled. This means that the closure expected to "catch" the error, but in your case, you forgot the do-try-catch rule.
Therefore you can try the following answer which will catch your errors:
do {
let imageAsData = try Data(contentsOf: imageURL)
let image = UIImage(data: imageAsData)
let ImageObject = Image()
ImageObject.image = image
self.arrayOfImgObj.append(ImageObject)
} catch {
print("imageURL was not able to be converted into data") // Assert or add an alert
}
You can then assert an error (for testing), or what I would personally do, is set up an alert.
This way the app wouldn't crash, but instead, notify the user. I find this very helpful when on the go and my device isn't plugged in - so I can see the error messages instead of a blank crash with no idea what happened.
This error can also happen if you have a non related compilation error in your closure body. For example, you may be trying to compare two or more non-boolean types.
extension Array where Element == Resistance {
init(_ points: [Point]) {
let peaks = points.beforeAndAfter { (before, current, after) -> Bool in
before < current && current > after
}
self = []
}
}
will produce Unable to infer closure type in the current context.
The correct code:
extension Array where Element == Resistance {
init(_ points: [Point]) {
let peaks = points.beforeAndAfter { (before, current, after) -> Bool in
before.value < current.value && current.value > after.value
}
self = []
}
}
In addition to ScottyBlades answer, I'd like to add two data points to the "experience". It looks like referencing a non-existent property using self inside the block is not handled nicely by the compiler.
Nice error inside the block:
// Setting a handler for an NWListener instance:
self.nwListener?.newConnectionHandler = { (_ connection: NWConnection) -> Void in
// Results in "Cannot find 'nonExistentProperty' in scope"
// in the line below:
guard let delegate = nonExistentProperty else { return }
}
Weird "Type of expression is ambiguous without more context" error: (note the new self in front of nonExistentProperty)
// Setting a handler for an NWListener instance:
// Results in "Type of expression is ambiguous without more context"
// at the equals sign below:
self.nwListener?.newConnectionHandler = { (_ connection: NWConnection) -> Void in
guard let delegate = self.nonExistentProperty else { return }
}
I'm trying to OCR my image using Firebase MLKit but it fails and return with error
Text detection failed with error: Failed to run text detector because self is nil.
/// Detects texts on the specified image and draws a frame for them.
func detectTexts() {
let image = #imageLiteral(resourceName: "testocr")
// Create a text detector.
let textDetector = vision.textDetector() // Check console for errors.
// Initialize a VisionImage with a UIImage.
let visionImage = VisionImage(image: image)
textDetector.detect(in: visionImage) { (features, error) in
guard error == nil, let features = features, !features.isEmpty else {
let errorString = error?.localizedDescription ?? "No results returned."
print("Text detection failed with error: \(errorString)")
return
}
// Recognized and extracted text
print("Detected text has: \(features.count) blocks")
let resultText = features.map { feature in
return "Text: \(feature.text)"
}.joined(separator: "\n")
print(resultText)
}
}
It looks like you need to keep a strong reference to textDetector, otherwise the detector gets released before the completion block can be called.
Changing your code a bit:
var textDetector: VisionTextDetector? // NEW
/// Detects texts on the specified image and draws a frame for them.
func detectTexts() {
// ... truncated ...
textDetector = vision.textDetector() // NEW
let visionImage = VisionImage(image: image)
textDetector?.detect(in: visionImage) { (features, error) in // NEW
// Callback implementation
}
}
You can also unwrap it to make sure it's not nil after you assign it:
guard let textDetector = textDetector else {
print("Error: textDetector is nil.")
return
}
I hope that helps!
VisionTextDetector is no more supported so you have to use VisionTextRecognizer.
Here is an example code and I hope its helpful
//MARK: Firebase var
lazy var vision = Vision.vision()
// replace VisionTextDetector with VisionTextRecognizer
var textDetector: VisionTextRecognizer?
override func viewDidLoad() {
super.viewDidLoad()
textDetector = vision.onDeviceTextRecognizer()
}
// also instead of using detect use process now
textDetector!.process(image) { result, error in
guard error == nil, let result = result else {
//error stuff
return
}
let text = result.text
self.textV.text = self.textV.text + " " + text
}
}
I am trying to activate the iPhone LED with this code (connected to a UIButton):
#IBAction func toggleFlash(sender: AnyObject) {
let device = AVCaptureDevice.defaultDeviceWithMediaType(AVMediaTypeVideo)
if (device.hasTorch) {
device.lockForConfiguration(nil)
if (device.torchMode == AVCaptureTorchMode.On) {
device.torchMode = AVCaptureTorchMode.Off
} else {
device.setTorchModeOnWithLevel(1.0, error: nil)
}
device.unlockForConfiguration()
}
}
Then I get the error:
fatal error: unexpectedly found nil while unwrapping an Optional value
For the following code:
if (device.hasTorch) {
It also says: EXC_BAD_INSTRUCTION (code=...)
What should I do, add delete?!!
THANK YOU!
defaultDeviceWithMediaType() returns nil if there is no device available for that media type. You must check to make sure there is a device before calling other methods on it
#IBAction func toggleFlash(sender: AnyObject) {
if let device = AVCaptureDevice.defaultDeviceWithMediaType(AVMediaTypeVideo) {
if (device.hasTorch) {
device.lockForConfiguration(nil)
if (device.torchMode == AVCaptureTorchMode.On) {
device.torchMode = AVCaptureTorchMode.Off
} else {
device.setTorchModeOnWithLevel(1.0, error: nil)
}
device.unlockForConfiguration()
}
}
}
With Swift 1.2, you can do the check with this code:
if let device = AVCaptureDevice.defaultDeviceWithMediaType(AVMediaTypeVideo) where device.hasTorch {
//do your work with device
} else {
NSLog("Device is nil or device does not have Torch")
}
In Swift 1.2, the pattern "if let" is more powerful. According to the release notes:
The “if let” construct has been expanded to allow testing multiple
optionals and guarding conditions in a single if (or while) statement
using syntax similar to generic constraints:
if let a = foo(), b = bar() where a < b,
let c = baz() {
}