Proper way to declare ExtAudioFileRef in swift 5 for macOS - swift

I have been working on an audio application where I can seek to a specific point in an ExtAudioFile and load a specific number of frames that represent a particular length (time) of playback into an AVAudioPCMBuffer and start playing it. If the user selects a checkbox during playback of that audio segment, the buffer is then fed the remaining contents of the audio file so it will play to the end.
However, I have hit a roadblock. I have found older examples of code that loads these resources. They way they're declaring the calls is not working in Swift 5 for me. I am getting errors. Specifically:
import Cocoa
import AVFoundation
import AudioToolbox
do {
var err:OSStatus = noErr
let url = URL(fileURLWithPath: "./audio files/myAudioFile.mp3")
let track = try AVAudioFile(forReading: url)
var trackRef = ExtAudioFileRef?
err = try ExtAudioFileOpenURL(url as CFURL, trackRef)
} catch {
print(error)
}
The first error I am getting is for trackRef. The editor is flagging this line as "Expected member name or constructor call after type name." But the example I was following only had the property declared as shown in the code above.
The next line err = try ExtAudioFileOpenURL(orl as CFURL, trackRef) has error "Cannot convert value of type 'ExtAudioFileRef?.Type' (aka 'Optional.Type') to expected argument type 'UnsafeMutablePointer<ExtAudioFileRef?>' (aka 'UnsafeMutablePointer<Optional>')."
The editor is suggesting I change trackRef declaration to ver trackRef = ExtAudioFileRef?() or var trackRef = ExtAudioFileRef?.self but neither of those are any help because if I try using the first suggestion I then get "Cannot invoke initializer for type 'ExtAudioFileRef?' with no arguments" and a gray note showing "1. Overloads for 'ExtAudioFileRef?' exist with these partially matching parameter lists: (Wrapped), (from: Decoder), (nilLiteral: ())." But the error for err = ExtAudioFileOpenURL(url as CFURL, trackRef) goes away. If I try using the second suggestion let trackRef = ExtAudioFileRef?.self there is no error on that line, but then I get an error on the err = ExtAudioFileOpenURL(url as CFURL, trackRef) line that reads "Cannot convert value of type 'ExtAudioFileRef?.Type' (aka 'Optional.Type') to expected argument type 'UnsafeMutablePointer<ExtAudioFileRef?>' (aka 'UnsafeMutablePointer<Optional>')"
I am not versed enough to know what these errors mean as I don't know what UnsafeMutablePointer is. I was just following the example code to try and achieve what I want to do. Unfortunately I've not been able to get any of the audio tools in Swift to do what I want to do and this is the next rabbit hole for me.
Thanks for any help.

I finally found some recent code that uses this in later Swift.
I do not need to initialize the trackRef property, which was what was causing the errors to appear in the declarations. I also didn't need the try method.
Here's the proper way to declare it:
var trackRef: ExtAudioFileRef?
err = ExtAudioFileOpenURL(url as CFURL, &trackRef)
Now for the next rabbit hole...

Related

Watson Assistant in Swift 4 Producing Error

I'm trying to connect an iOS project, coded in Swift, to an instance of a Watson Assistant that I've already created. The issue is, I can't get past a "Contextual Closure type" error in compiling.
I'm relatively new to Swift and I have yet to come across a solution.
The error arises in the block of code provided by IBM themselves (here's the link: https://console.bluemix.net/docs/swift/machine_learning/conversation.html#before-you-begin). The one thing I could find was that this is likely a result of the update to Swift 4. Below is the function that's producing the error; more specifically, it's the "response in" statement, after the third comment.
func assistantExample() {
// Assistant credentials
let username = "shawn.soneja85#gmail.com"
let password = "Shawn8135!"
let workspace = "199b1f99-b28c-4b3f-b610-5933328141d5"
// instantiate service
let assistant = Assistant(username: username, password: password, version: "2018-03-01")
// start a conversation
assistant.message(workspaceID: workspace) { response in
print("Conversation ID: \(response.context.conversationID!)")
print("Response: \(response.output.text.joined())")
// continue assistant
print("Request: turn the radio on")
let input = InputData(text: "turn the radio on")
let request = MessageRequest(input: input, context: response.context)
assistant.message(workspaceID: workspace, request: request) { response in
print("Response: \(response.output.text.joined())")
}
}
}
Here's the error itself:
Contextual closure type '(RestResponse?, WatsonError?) -> Void' (aka '(Optional>, Optional) -> ()') expects 2 arguments, but 1 was used in closure body
Update:
I've tried replacing "response" with "(response, error)", but that leads to the following error messages:
Value of type 'RestResponse?' has no member 'context'
Value of type 'RestResponse?' has no member 'output'
And with "(error, response)", it leads to the following error:
Value of type 'WatsonError?' (aka 'Optional') has no member 'output'
Value of type 'WatsonError?' (aka 'Optional') has no member 'context'
Here is documentation on .message function:
first screenshot
second screenshot
Thanks in advance for the help!
RestResponse contains a result of the .message call in a field called result. So to access the output or context, use response.result.output and response.result.context.
It would be helpful if you gave more description like:
Swift version you are using to compile your target
Line number of the error
That being said, I think your problem is in the nested .message method, i've copied your code above but deleted some lines to try and make it clear (at least what I am proposing), you may have added the second parameter to the callback in the first call to .message but had forgotten to do so in the second (nested) call, the one where you pass in the request. So you might have added the second, error parameter in the first call but got the same exact error message for a missing parameter because you forgot to do the same thing for the nested call. I hope this helps :)
// start a conversation
assistant.message(workspaceID: workspace) { response, error in
let input = InputData(text: "turn the radio on")
let request = MessageRequest(input: input, context: response.context)
assistant.message(workspaceID: workspace, request: request) { response, error in
print("Response: \(response.output.text.joined())")
}
}

Swift MetalKit unknknown return type MTKMesh.newMeshes

Up until now I have been following a tutorial (released around the time of Metal 1), to learn Metal. I haven't encountered any errors I couldn't figure out until this point. I am trying to execute this code
var meshes: [AnyObject]?
//code
let device = MTLDevice() //device is fine
let asset = MDLAsset() //asset works fine
do{
meshes = try MTKMesh.newMeshes(asset: asset, device: device)
} catch //...
The error i'm getting is Cannot assign value of type '(modellOMeshes: [MDLMesh], metalKitMeshes: [MTKMesh])' to type '[AnyObject]?'
What is type of MTKMesh.newMeshes, and how can I store it in a variable? I tried casting it as! [AnyObject], but then xcode tells me that this cast would fail every time.
The return type of that method is ([MDLMesh], [MTKMesh]), a tuple comprised of an array of MTLMeshes and an array of MTKMeshes. The reason for this is that you might want the original collection of MDLMesh objects contained in the asset, in addition to the MTKMesh objects that are created for you.
So, you can declare meshes like this:
var meshes: ([MDLMesh], [MTKMesh])
Or, if you don't care about the original MDLMeshes, you can "destructure" the tuple to get just the portion you care about into a variable of type [MTKMesh]:
var meshes: [MTKMesh]
(_, meshes) = try MTKMesh.newMeshes(asset: asset, device: device)
As the function signature and the compiler error clearly show, the return type is (modelIOMeshes: [MDLMesh], metalKitMeshes: [MTKMesh]), so you should declare meshas accordingly:
var meshes: (modelIOMeshes: [MDLMesh], metalKitMeshes: [MTKMesh])?
The type is a named tuple containing two Arrays, holding MDLMesh and MTKMesh instances respectively.

ReactiveKit Bond KVO observe UserDefaults

I was previously using RxSwift and I decided I did not want to use it anymore and was able to convert everything over to Bond which I am much more familiar with. Since the new changes though to Bond v5, I cannot seem to figure out how to observe values in UserDefaults. The following code ends up giving me a fatal error.
userDefaults.reactive
.keyPath(LocationManager.HomeLocationKey, ofType: String.self, context: .immediateOnMain)
.map(self.initLocation(from:))
.bind(to: self.homeLocation)
userDefaults is a reference to UserDefaults.standard and LocationManager.HomeLocationKey is a string. I am providing the initLocation function below as I know it will be asked for. Below that function I will post the error that I am receiving after the app starts up.
func initLocation(from string: String?) -> Location?
{
guard let dataString = string
else { log.warning("Location data did not exist, returning nil"); return nil }
let json = JSON.parse(dataString)
return Location(from: json)
}
Error:
fatal error: Could not convert nil to String. Maybe `dynamic(keyPath:ofExpectedType:)` method might be of help?): file /Users/sam/Documents/iOS Apps/Drizzle/Pods/Bond/Sources/Shared/NSObject+KVO.swift, line 58
It might not be obvious, but if the observed value can be nil, the ofType argument must be an Optional type. In your case, that would be:
userDefaults.reactive
.keyPath(LocationManager.HomeLocationKey, ofType: Optional<String>.self, context: .immediateOnMain)
...

Swift: can not invoke method with correct arguments?

I am trying to find a count of entities which satisfy predicate. According to documentation and "header" files, this should work:
let fetch = NSFetchRequest<NSFetchRequestResult>(entityName: "FileRecord")
let ctx: NSManagedObjectContext = GetCtx()
let res = try ctx.count(for: fetch)
however I get compile error:
Cannot invoke 'count' with an argument list of type '(for: NSFetchRequest<NSFetchRequestResult>)'
however when I create the fetch request from FileRecord like this instead:
let fetch: NSFetchRequest<FileRecord> = FileRecord.fetchRequest()
I get the following error:
Cannot convert value of type 'NSFetchRequest<FileRecord>' to expected argument type 'NSFetchRequest<NSFetchRequestResult>'
Please anyone got an idea what can be wrong? I am a decent C++ language lawyer but I am just a novice with Swift...
EDIT: SOLVED
My example above was wrong. In reality I had code functionally identical to:
let res: UInt64 = try ctx.count(for: fetch)
since count returns Int, the function did not match. The error message was not specific enough for me to see it immediately. Thanks to all who have tried to help :)

Swift Compiler Error when accessing array - Exit code 254

I am quite new to swift and got a pretty weird compiler error:
Command
/Applications/Xcode6-Beta5.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/swiftc
failed with exit code 254
The Error occours when I ad the following lines to my code:
var response = HoopsClient.instance().collections["posts"]
response = response["_id"]
when I remove the second line everything compiles fine. I don't get it ^^
edit: The reason is probably that "response" is of type "AnyObject" according to the compiler... but shouldn't that be detected by xcode or give me a runtime error instead of this compiler error?
Try casting response as the type you're expecting. From what you're trying to do, instance().collections I would assume that it should return some type of dictionary.
var response = HoopsClient.instance().collections["posts"] as NSDictionary
That way, response now can handle subscripts so you could now (in theory) do:
response = response["_id"]
However
The error you get is regarding bad access to an array. This makes me think that instance().collections actually returns an array of some sort, containing Post objects.
Arrays in Swift can only handle Integer subscripts. If you want to access the information of a Post in the array, you can do something like this:
for post: Post in response {
println(post._id)
}
I know this is a long shot, but hope it helps.
Swift tends to throw error when it cant infer the type of an object, what you could probably do is add a conditional cast as follows
Im assuming that HoopsClient.instance().collections["posts"] is either a Dictionary or an Array
var response = HoopsClient.instance().collections["posts"]
if response is NSArray {
let item = response.objectAtIndex(0)
let reponseId: Post = item
}
if response is NSDictionary {
let item = response.objectForKet("_id")
let reponseId: Post = item
}
Any way, in my experience you should try to cast your variables when assigning from types that return AnyObject, xcode doesn't handle very well type inferring and when it's unable to infer the type the interface starts to throw error, like text editor uncoloring the code.