Optional value nil found after using AudioFileGetProperty() with kAudioFilePropertyDataFormat - swift

I'm trying to use swift AudioToolbox API to playback an audio file. However, when I get the AudioStreamBasicDescription using AudioFileGetProperty() the app crashes when I try to unwrap the value, saying "Unexpectedly found nil while unwrapping an optional value". This makes no sense because:
1) The OSStatus after I call AudioFileGetProperty() is zero.
2) I can see that the value is "nil" at first in the console, but after calling AudioFileGetProperty() it changes to "Some" and suddenly it is populated with values.
Perhaps am I using pointers incorrectly? Am I using optionals incorrectly?
func playAudioFileWithToolbox(){
var aqData = AQPlayerState()
let url2 = bundle.path(forResource: "dave_speaking", ofType: "m4a")!
var filePathArray = Array(url2.utf8)
let audioFileUrl = CFURLCreateFromFileSystemRepresentation(nil, &filePathArray, filePathArray.count, false)
//Problem: how do we pass aqData.mAudioFile? Initially it is nil
//We are supposed to pass by reference
let status = AudioFileOpenURL(audioFileUrl!, permissions, 0, &(aqData.mAudioFile))
var dataFormatSize:UInt32 = UInt32(MemoryLayout<AudioStreamBasicDescription>.size)
//Here I populate aqData.mDataFormat
var propertyStatus = AudioFileGetProperty(aqData.mAudioFile!, kAudioFilePropertyDataFormat, &dataFormatSize, &(aqData.mDataFormat))
//Next line crashes saying that it is unwrapping an optional value
var audioStreamDescription = aqData.mDataFormat!
}
struct AQPlayerState{
var mDataFormat:AudioStreamBasicDescription?
var mQueue:AudioQueueRef?
var mBuffers:AudioQueueBufferRef?
var mAudioFile: AudioFileID?
var bufferByteSize:UInt32 = 0
var mCurrentPacket:Int64 = 0
var mNumPacketsToRead:UInt32 = 0
var mPacketDescs : UnsafeMutablePointer<AudioStreamPacketDescription>?
var mIsRunning : Bool = false
init(){
}
}

So I figured out I was using a combination of pointers and optional values incorrectly. Because mDataFormat was by itself an optional:
var mDataFormat:AudioStreamBasicDescription?
passing a reference to it didn't make much sense, i.e., &mDataFormat.
Therefore I changed this variable to make it non-optional:
var mDataFormat:AudioStreamBasicDescription = AudioStreamBasicDescription()
That way, there was memory allocated to it, as well as an address, and it now made sense to do something like this:
&aqData.mDataFormat
var propertyStatus = AudioFileGetProperty(aqData.mAudioFile!, kAudioFilePropertyDataFormat, &dataFormatSize, &aqData.mDataFormat)
Anyway I am still learning how to combine optionals with pointers so any additional feedback you can give me would help.

Related

No exact matches in call to initializer when initializing Data in AppStorage

I'm learning how to store custom types in AppStorage, and came across an issue. In this simplified example, I'm trying to save an empty Int array to AppStorage once the view is created.
The following code gives me the error, No exact matches in call to initializer . I know that this error usually means there are mismatching types somewhere, but I'm not sure what the types should be, or how to fix it.
struct test: View {
init() {
let emptyList = [Int]()
guard let encodedList = try? JSONEncoder().encode(emptyList) else { return }
self.storedList = encodedList
}
#AppStorage("stored_list") var storedList: Data //NO EXACT MATCHES TO CALL IN INITIALIZER
//"body" implementation not shown
}
Why is this error occurring, and how can I fix it?
It should be either with default value or optional, so correct variants are
#AppStorage("stored_list") var storedList: Data = Data()
or
#AppStorage("stored_list") var storedList: Data?

initialise Codable result with var

I need to initialise the result of JSONDecoder in a var object defined outside the API Call.
apiService.GETAPI(url: apiStr, completion: {(success, result) in
if(success) {
let apiResponse = result.value as! NSDictionary
let data = apiResponse.value(forKey: "data") as! NSDictionary
do {
let profileData = try JSONSerialization.data(withJSONObject: data.value(forKey: "profile"), options: .prettyPrinted)
print(profileData)
let profile = try JSONDecoder().decode(Profile.self, from: profileData)
print(profile.name)
}
catch {
print("json error: \(error.localizedDescription)")
}
}
completion(success)
})
But I am unable to do so. This is my Profile Codable struct
struct Profile : Codable {
var id : Int
var name : String
var member_id : Int
var category_id : Int
var membership_id : Int
var information : String
var city : String
var love_count : Int
var vendor_price : String
var locality_name : String
var phone : [String]
var address : [Address]?
var status : Int?
var managed_by_wmg : Int?
}
How to do it. I need it to be var since I need to perform operation and access it later in the other code.
As we have already discussed in the comments of your question, you need to declare variable of Profile type outside the closure.
So now the problem become "How to change Profile struct, so I can declare variable of it?"
For this you have several options. I will list them and comment on which to choose and why.
Option 1
Add default values to all the variables of Profile struct as so: var id : Int = 0, so you can declare it later with var profile: Profile?. With this solutions you need to have some knowledge about the objects you are expecting and their default values in a way they make sense to your business logic. Example for such default values are "" for string or 0 integer. This might seem good but yet their is better solution.
Option 2
Make ALL the variables of Profile optional as so: var id : Int?. This might sounds strange at first, but is the optimal solution for working with server data. So this method has several benefits:
It will never crash, no matter what the server sends you as a data
All the variables have default values equaling nil
You do not need to think about your business logic and what default value suits your needs
However, with this method there is one drawback: some properties that with your logic could never be nil will have nil initial value. So you need to add validations for unwrapping the nullable properties.
Option 3 Add explicit unwrapping to the variable type as so var id : Int!. Note this also adds nil as initial value to your properties, but tells the compiler that in every time you are gonna use them, they will not be nil. I would personally not recommend this method, because if the variable is not received from the server, or the parsing fails, or something else unexpected happens, your app will crash with found nil while unwrapping optional value. For reference you might have noticed all the IBOutlets are defined this way.
Having said all that, I would recommend you going with Option 2, which best suits server communication, but the choice is yours!
Happy coding.
I have found two solutions to my question. Thanks to #dvp.petrov.
Solution 1 var profile : Profile! comes handy but it becomes difficult if this is not an optional variable and have to be used at many places. One will have to put lot of checks and unwrap it every time. This is easy to use when one has to use it at very less places
Solution 2 : Create an init function giving default values to all the variable and then you can create var profile : Profile(). This way your object will not be nil and will be able to use it at places.
struct Profile : Codable {
var id : Int
var name : String
var member_id : Int
init() {
self.id = 0
self.name = ""
self.member_id = 0
}

How to use UnsafeMutablePointer<OpaquePointer> in Swift?

How does one use an UnsafeMutablePointer<OpaquePointer> in Swift with some Core Foundation framework? Why have an UnsafeMutablePointer<OpaquePointer>?
Given, general: some UnsafeMutablePointer<SomeType> where typealias SomeType = OpaquePointer
Specific Example API
// SOURCE: import ApplicationServices.PrintCore
typealias PMPrinter = OpaquePointer
func PMSessionGetCurrentPrinter(_ printSession: PMPrintSession, _ currentPrinter: UnsafeMutablePointer<PMPrinter>)
func PMPrinterGetPaperList(PMPrinter, UnsafeMutablePointer<Unmanaged<CFArray>?>)
Specific Example Use Case: get list of papers supported by a printer
let printInfo = NSPrintInfo.shared()
let printSession = PMPrintSession(printInfo.pmPrintSession())
var currentPrinterOptional: PMPrinter? = nil
PMSessionGetCurrentPrinter(printSession, &currentPrinterOptional!)
guard let currentPrinter = currentPrinterOptional else { return }
// Get the array of pre-defined PMPapers this printer supports.
// PMPrinterGetPaperList(PMPrinter, UnsafeMutablePointer<Unmanaged<CFArray>?>)
var paperListUnmanaged: Unmanaged<CFArray>?
PMPrinterGetPaperList(currentPrinter, &paperListUnmanaged)
guard let paperList = paperListUnmanaged?.takeUnretainedValue() as [AnyObject]? else { return }
Observed Errors
What compiles does not run. What seems like (maybe) reasonable syntax does not compile.
The above example gets the following (expected) Runtime "fatal error: unexpectedly found nil while unwrapping an Optional value".
Some select other attempts:
// Compile Error: Address of variable 'currentPrinter' taken before is is initialized
var currentPrinter: PMPrinter
PMSessionGetCurrentPrinter(printSession, &currentPrinter)
// Compile Error: Nil cannot initialze specified type 'PMPrinter' (aka 'OpaquePointer')
var currentPrinter: PMPrinter = nil
PMSessionGetCurrentPrinter(printSession, &currentPrinter)
// Compile Error: Variable 'currentPrinterPtr' used before being initialized
var currentPrinterPtr: UnsafeMutablePointer<PMPrinter>
PMSessionGetCurrentPrinter(printSession, currentPrinterPtr)
// Compile OK: actually compiles
// Runtime Error: unexpectedly found nil while unwrapping an Optional value
var currentPrinterOptional: PMPrinter? = nil
PMSessionGetCurrentPrinter(printSession, &currentPrinterOptional!)
Resources
Apple: Core Printing ⇗
Apple: Using Swift with Cocoa and Objective-C ⇗
While the docs have useful information, a workable implementation for UnsafeMutablePointer<PMPrinter> with typealias as UnsafeMutablePointer<OpaquePointer> has been elusive.
PMPrinter and PMPaper are defined in the PrintCore framework
as pointer to an "incomplete type"
typedef struct OpaquePMPrinter* PMPrinter;
typedef struct OpaquePMPaper* PMPaper;
Those are imported into Swift as OpaquePointer, and are a bit
cumbersome to use.
The second argument to PMSessionGetCurrentPrinter() is a pointer to
a non-optional PMPrinter variable, and in Swift it must be
initialized before being passed as an inout argument. One possible way
to initialize a null-pointer is to use unsafeBitCast.
The easiest way to get the PMPaper objects from the array seems to
be to use CFArrayGetValueAtIndex() instead of bridging it to a
Swift array. That returns a UnsafeRawPointer which can be converted
to an OpaquePointer.
This worked in my test:
let printInfo = NSPrintInfo.shared()
let printSession = PMPrintSession(printInfo.pmPrintSession())
var currentPrinter = unsafeBitCast(0, to: PMPrinter.self)
PMSessionGetCurrentPrinter(printSession, &currentPrinter);
var paperListUnmanaged: Unmanaged<CFArray>?
PMPrinterGetPaperList(currentPrinter, &paperListUnmanaged)
guard let paperList = paperListUnmanaged?.takeUnretainedValue() else {
fatalError()
}
for idx in 0..<CFArrayGetCount(paperList) {
let paper = PMPaper(CFArrayGetValueAtIndex(paperList, idx))!
var width = 0.0, height = 0.0
PMPaperGetWidth(paper, &width)
PMPaperGetHeight(paper, &height)
print(width, height)
}

Swift EXC_BAD_ACCESS with a corrupted object?

For some strange reason, I'm encountering an EXC_BAD_ACCESS, specifically in unwrapping and referencing a field. (Reproducible on the Xcode 7 GM.)
Here's the relevant code:
// FIXME: BUGGY
let conv_id = client_conversation.conversation_id //!.id
print("ABOUT TO DIE: \(conv_id?.id)")
if conv_id!.id as? String != nil {
conv_id!.id = "hi"
}
It crashes at the print() statement. Not sure what I can adequately do to fix this. I've tried the malloc() debugging, Zombie objects, and hand-debugging via backtrace.
I've added the definition of these objects:
class Message : NSObject {
required override init() {
super.init()
}
}
class CONVERSATION_ID : Message {
var id: NSString = ""
}
class CLIENT_CONVERSATION : Message {
var conversation_id: CONVERSATION_ID?
var type = ConversationType()
var name: NSString?
var self_conversation_state = CLIENT_CONVERSATION_INTERNAL_STATE()
var read_state = [CLIENT_CONVERSATION_READ_STATE]()
var current_participant = [USER_ID]()
var participant_data = [CLIENT_CONVERSATION_PARTICIPANT_DATA]()
}
Another example issue: while print(conv_id!) prints
(
"sample string"
)
I can't seem to be able to access the string directly.
Any time you say ! you are inviting a crash. Rewrite your code so that ! never appears. Know your Optionals and unwrap every single one of them safely. Learn about how to compare an Optional with nil before unwrapping, or how to use the if let construct.
Also, note that this line is sheer nonsense (what I call a "false cast"):
if conv_id!.id as? String != nil {
An NSString is always a String; I am surprised that the compiler is not warning you about this. Thus, the test is meaningless.
Your code should therefore read like this:
let conv_id = client_conversation.conversation_id
conv_id?.id = "hi"
Notice that there are no false casts and exclamation marks.

Difference between optional values in swift?

What is the difference between:
var title:String? = "Title" //1
var title:String! = "Title" //2
var title:String = "Title" //3
What am I saying if I were to set title in each way and am I forced to unwrap each variable in a different way?
Think about ? and ! like a box that might have a value or not.
I recommend this article.
Optional box that might have value or might not, and that optional box is not unwrapped.
var title:String? = "Title" //second and third picture
You use unwrapped value like that:
if let title = title {
//do sth with title, here is the same like let title: String = "Title"
}
Optional box that might have a value or might not, and that optional box is actually unwrapped. If there is a value and you access that value, that is ok (second image, just replace ? with !), but if there is no value, then app crash (third image, just replace ? with !)
var title:String! = "Title"
That variable have a value for sure, and you cannot assign to this value nil (because it is not optional). Optional means that there is a value or there is no value (nil):
var title:String = "Title" //first picture
`var title:String? = "Title"`
title currently has a value of Title, but in the future it could possibly be nil. I will need to unwrap it using optional binding:
if let unwrappedTitle = title {
println(unwrappedTitle)
}
Or by forcing the unwrap with the ! character
let unwrappedTitle = title!
The above will crash if title is nil
`var title:String! = "Title"`
title currently has a value of "Title". It could possibly be nil, but I know that it never will be when I am using it. You don't need to unwrap this with optional binding or by forcing the unwrap with the ! character.
Your program will crash if this value is ever accessed while nil, but the compiler will let you set this value to nil.
`var title:String = "Title"`
title currently has a value of "Title". This may change, but the variable title will always have some string value. I don't need to check for nil with optional binding or by forcing an unwrap. The compiler will not let you build if you try to set title to nil.
var title:String? = "Title" //1 Nil Possible-Force Unwrap needed-Nil checking when use
var title1:String! = "Title"//2 Nil Possible-Force Unwrap not needed-Nil cheking when Use
var title2:String = "Title" //3 Nil Not possible as its initailize when declared-No force unwrap needed-No Nil Cheking is needed.