I have converted an Objective-C script to Swift for forming header of an AAC frame. However the code fails to run in the app and crashes with an EXC_BAD_ACCESS. Copying the code in to playground outputs what I expect with no errors. Not sure where to go with this, because it seems like it should work. I could always use the Objective-C version but that feels like going around the issue.
func adtsDataForPacketLength(packetLength: Int) -> NSData {
let adtsLength = 7
let profile = 2
let freqIdx = 4
let chanCfg = 1
let fullLength = adtsLength + packetLength;
var packet = [UInt8]()
packet.append(UInt8(0xFF))
packet.append(UInt8(0xF9))
packet.append(UInt8(((profile-1)<<6) + (freqIdx<<2) + (chanCfg>>2)))
packet.append(UInt8(((chanCfg&3)<<6) + (fullLength>>11)))
packet.append(UInt8((fullLength&0x7FF) >> 3))
packet.append(UInt8(((fullLength&7)<<5) + 0x1F))
packet.append(0xFC)
return NSData(bytes: packet, length: packet.count)
}
Related
I've been making fun small games for myself over the last few years, everything I know about coding has been read online, so I'm very inexperienced. I have recently started working with SceneKit and get lots of no reoccuring bad access errors. They all seem to come in my if let n = scene.rootnode.childnode calls which you can see below and I'm not sure why. I know the node that I'm calling exists and has the correct name. I can run the exact same scenario 5 times in a row and 2 of them will give me the bad access error. The exact error code is EXC_BAD_ACCESS (code=EXC_I386_GPFLT). I have read a few things about this error and have tried command-K to clear console and that didn't help. I get this error on both simulator and real device. Any advice or knowledge would be appreciated. Thanks.
#objc func waveTick() {
let teamDef = -1*teamInv + 3
var num1 = 0
let nodesCur = actNodes[teamInv-1]
while (num1 < nodesCur.count){
num1 += 1
if let n = scene.rootNode.childNode(withName: "NODE" + String(nodesCur[num1-1]), recursively: false) as? HelpNode {
if (n.tick == tick && n.invador) {
enemyBrain(enemy: n)
}
}
}
there. I am a beginner in Swift and am trying to convert an older program to Swift3. I´ve managed to fix a bunch of errors, but I cannot get this function to work.
fileprivate func extractEntitlements(_ entitlementData: Data) -> NSDictionary? {
var originalEntitlementsData = entitlementData
let xmlStart = "<?xml".data(using: String.Encoding.ascii, allowLossyConversion: true)
let bytes = (originalEntitlementsData as NSData).bytes
for i in 0...(originalEntitlementsData.count - xmlStart!.count) {
if memcmp((xmlStart! as NSData).bytes, bytes + i, Int(xmlStart!.count)) == 0 {
let end = originalEntitlementsData.count - i
**originalEntitlementsData = originalEntitlementsData.subdata(in: NSMakeRange(i, end))**
break;
}
}
return NSString(data: originalEntitlementsData, encoding: String.Encoding.ascii.rawValue)?.propertyList() as? NSDictionary
}
Here is the error I get:
There are a bunch of questions regarding this error, but I am not being successful implementing a solution. Any tips on how I should proceed?
Thanks guys!
Ranges are more complicated and simpler at the same time in swift.
You want subdata(in: start..<end), which makes a Range<Int>, which is the type you need. However, in this case start and end refer to the beginning and end indexes of the range, not the location and length as you pass to NSMakeRange().
As #jrturton already said, subdata(in:) takes a Range<Int> argument,
so it should be
originalEntitlementsData = originalEntitlementsData.subdata(in: i..<i+end)
in your case. But note that all the conversions to NSData, taking
the .bytes, explicit loop and memcmp are not needed if you
take advantage of the existing range(of:) method of Data:
var originalEntitlementsData = entitlementData
let xmlStart = "<?xml".data(using: .utf8)!
if let range = originalEntitlementsData.range(of: xmlStart) {
originalEntitlementsData = originalEntitlementsData.subdata(in: range.lowerBound..<originalEntitlementsData.endIndex)
// Alternatively:
// originalEntitlementsData.removeSubrange(0..<range.lowerBound)
}
In Objective-C, you can print the call stack by doing the following:
NSLog(#"%#", [NSThread callStackSymbols]);
How do you do this in Swift without using Foundation class?
As Jacobson says, use the following:
Swift 2:
print(NSThread.callStackSymbols())
Swift 3 / Swift 4:
print(Thread.callStackSymbols)
That's Swift code. It's using a Foundation method, but so does 90%+ of what you do on iOS.
EDIT:
Note that the formatting looks better if you use:
Thread.callStackSymbols.forEach{print($0)}
From the debugger command line you can type
e Thread.callStackSymbols.forEach{print($0)}
For Swift 3 use:
print(Thread.callStackSymbols)
or for better formatting
for symbol: String in Thread.callStackSymbols {
print(symbol)
}
This improves the output a little.
for symbol: String in NSThread.callStackSymbols() {
NSLog("%#", symbol)
}
print(Thread.callStackSymbols.joined(separator: "\n"))
With this code, one can see the calls in different lines each.
1 MyApp 0x0000000100720780 $s9MyAppModule....
2 CoreFoundation 0x0000000181f04c4c EA9C1DF2-94C7-379B-BF8D-970335B1552F + 166988
3 CoreFoundation 0x0000000181f99554 EA9C1DF2-94C7-379B-BF8D-970335B1552F + 775508
4 CoreFoundation 0x0000000181f6eb34 EA9C1DF2-94C7-379B-BF8D-970335B1552F + 600884
5 CoreFoundation 0x0000000181f19754 _CFXNotificationPost + 696
6 Foundation 0x0000000183634138 86D8A58D-B71F-34C6-83E0-014B2B835F1D + 106808
Here's a great utility class I found on github:
https://github.com/nurun/swiftcallstacktrace
You get a tuple (class,method) of any stack trace symbol so you can do a clean printout.
CallStackAnalyser.classAndMethodForStackSymbol(NSThread.callStackSymbols()[2])
Edit: swift 4.1 update
https://github.com/GDXRepo/CallStackParser
I needed to write the callstack to a log file so I tweaked it like so.
var ErrorStack = String()
Thread.callStackSymbols.forEach {
print($0)
ErrorStack = "\(ErrorStack)\n" + $0
}
Thread.callStackSymbols() is nice to have. But the traceback is ugly. Demangling would be nice. The Swift 4.1+ demangler linked in #MikeS's answer is extremely comprehensive and impressive, but it's also over 4000 lines of code, overkill if you just need app, class and method, and it's quite a lot to add to a project, which I'd prefer to not to risk forgetting not to ship my app with :-)
This is a quick prototype of something that does some basic demangling of appname, class and method (which are the easy part to figure out). It's not polished. For example, it doesn't check for nil/failures in the regex ops, since it just gets a line from the callstack, which should be consistent enough to avoid problems. However, improved versions of it are welcome answers.
I added it to a class I named Debug, where I keep other debugging stuff, and invoke it from wherever in my app as:
Debug.whence()
... note: "where" is a Swift reserved word, and whence means basically the same thing.
It prints a line of this form (only one line, not full stack):
EventEditorViewController.configureNavigationItem():419 I'll probably add an argument to take an optional object arg and then do a refined display of the object and its address without some of the parameters and syntax swift's builtin obj dump logging does, so that it would display obj info and where it is being traced.
This probably can only parse lines inside the app. It probably can't demangle non-Swift calls (like Foundation), not sure. If you need a more comprehensive demangler, check #MikeS's answer.
static func whence(_ lineNumber: Int = #line) {
func matchRegex(_ matcher: String, string : String) -> String? {
let regex = try! NSRegularExpression(pattern: matcher, options: [])
let range = NSRange(string.startIndex ..< string.endIndex, in: string)
guard let textCheckingResult = regex.firstMatch(in: string, options: [], range: range) else {
return nil
}
return (string as NSString).substring(with:textCheckingResult.range(at:1)) as String
}
func singleMatchRegex(_ matcher: String, string : String) -> String? {
let regex = try! NSRegularExpression(pattern: matcher, options: [])
let range = NSRange(string.startIndex ..< string.endIndex, in: string)
let matchRange = regex.rangeOfFirstMatch(in: string, range: range)
if matchRange == NSMakeRange(NSNotFound, 0) {
return nil
}
return (string as NSString).substring(with: matchRange) as String
}
var string = Thread.callStackSymbols[1]
string = String(string.suffix(from:string.firstIndex(of: "$")!))
let appNameLenString = matchRegex(#"\$s(\d*)"#, string: string)!
let appNameLen = Int(appNameLenString)!
string = String(string.dropFirst(appNameLenString.count + 2))
let appName = singleMatchRegex(".{\(appNameLen)}", string: string)!
string = String(string.dropFirst(appNameLen))
let classNameLenString = singleMatchRegex(#"\d*"#, string: string)!
let classNameLen = Int(classNameLenString)!
string = String(string.dropFirst(classNameLenString.count))
let className = singleMatchRegex(".{\(classNameLen)}", string: string)!
string = String(string.dropFirst(classNameLen))
let methodNameLenString = matchRegex(#".(\d*)"#, string: string)!
let methodNameLen = Int(methodNameLenString)!
string = String(string.dropFirst(methodNameLenString.count + 1))
let methodName = singleMatchRegex(".{\(methodNameLen)}", string: string)!
let _ = appName
print("\(className).\(methodName)():\(lineNumber)")
}
is there any possibility to create a custom log function?
This is how the default println("hello world") looks like:
2015-03-04 18:33:55.788 MyApp[12345:671253923] Hello World
I would like to output something like:
18:33 MyClass > myFunc [line 1] Hello World
First, for the time, you can get the current hour and minute as String:
func printTime()->String{
let date = NSDate()
let calendar = NSCalendar.currentCalendar()
let components = calendar.components(.CalendarUnitHour | .CalendarUnitMinute, fromDate: date)
let hour = components.hour
let minutes = components.minute
return "\(hour):\(minutes)"
}
And for the function etc. you can use the Swift Literal Expressions __FILE__, __FUNCTION__ and __LINE__.
But you don't want to set it each time you want to log. So you could do something like that:
func prettyPrint(print: String, file:String = __FILE__, functionName: String = __FUNCTION__, line:Int = __LINE__) {
println("\(printTime()) \(file) > \(functionName) [line \(line)] \(print)")
}
You call prettyPrint like that:
prettyPrint("hey")
And you will get the following output:
/Path/To/Your/File/MyClass.swift > hello [line 81] hey
But as you only want the name of your class, you can remove the path with the following function:
func getFile(path:String = __FILE__)->String{
var parts = path.componentsSeparatedByString("/")
return parts[parts.count-1]
}
Or, as ChikabuZ mentioned in his answer you can directly check the class:
let className = NSStringFromClass(self.classForCoder).pathExtension
Final Function
And here the final function(s):
func getFile(path:String = __FILE__)->String{
var parts = path.componentsSeparatedByString("/")
return parts[parts.count-1]
}
func prettyPrint(print: String, functionName: String = __FUNCTION__, line:Int = __LINE__) {
println("\(printTime()) \(getFile()) > \(functionName) [line \(line)] \(print)")
}
func printTime()->String{
let date = NSDate()
let calendar = NSCalendar.currentCalendar()
let components = calendar.components(.CalendarUnitHour | .CalendarUnitMinute, fromDate: date)
let hour = components.hour
let minutes = components.minute
return "\(hour):\(minutes)"
}
And the result will be:
MyClass.swift > hello [line 81] hey
You should also note #emaloney's answer to this question. Specifically that
println()-based solutions result in output being captured by the Apple System Log (ASL).
Ideally switch to NSLog or a full blown logging system
You should make an extension to NSObject, something like this:
class MyClass: NSObject
{
func myFunc()
{
myPrint("Hello World")
}
}
extension NSObject
{
func myPrint(text: String)
{
let timeFormatter = NSDateFormatter()
timeFormatter.dateStyle = NSDateFormatterStyle.NoStyle
timeFormatter.timeStyle = NSDateFormatterStyle.ShortStyle
let time = timeFormatter.stringFromDate(NSDate())
let className = NSStringFromClass(self.classForCoder).pathExtension
let function = __FUNCTION__
let line = "\(__LINE__)"
let result = time + " " + className + " > " + function + " " + line + " " + text
println(result)
}
}
let myClass = MyClass()
myClass.myFunc()
Unfortunately, none of the println()-based solutions result in output being captured by the Apple System Log (ASL).
The ASL is the logging facility provided by the Mac OS and iOS that is used by NSLog() (and on a Mac is visible through the Console application). Because NSLog() uses ASL, log entries recorded by NSLog() will be visible through the device console. Messages logged through println() will not be captured in ASL, and as a result, provide no opportunity to go back to the console for diagnostic purposes after something has happened.
There are two big downsides to NSLog(), however: (1) you can't customize the output format, and (2) it does a lot of work on the calling thread and can therefore negatively impact performance.
CleanroomLogger is a new Swift-based open-source API for logging. If you're familiar with log4j or CocoaLumberjack, then you'll understand CleanroomLogger.
You can customize your own output format by providing your own LogFormatter implementation to ensure that your log messages are formatted exactly as you want.
For more information on CleanroomLogger, visit the GitHub project page.
General question: I have an object which I want to convert to a ConstUnsafePointer. Everything I've tried seems to fail...how do I do it? I was able to do this previously in DP2, but cannot work it out in DP3.
Previously, I had code which looked like this:
var bpData = AUSamplerBankPresetData(bankURL: Unmanaged<CFURL>(_private: soundBankURL), bankMSB: UInt8(kAUSampler_DefaultMelodicBankMSB), bankLSB: UInt8(kAUSampler_DefaultBankLSB), presetID: presetID, reserved: 0)
let bpDataPointer: CConstVoidPointer = &bpData
// set the kAUSamplerProperty_LoadPresetFromBank property
result = AudioUnitSetProperty(samplerAudioUnit,
UInt32(kAUSamplerProperty_LoadPresetFromBank),
UInt32(kAudioUnitScope_Global),
0, bpDataPointer, 8)
However, now CConstVoidPointer is no longer around and has been replaced by ConstUnsafePointer. The AudioUnitSetProperty method looks like this:
func AudioUnitSetProperty(inUnit: AudioUnit, inID: AudioUnitPropertyID, inScope: AudioUnitScope, inElement: AudioUnitElement, inData: ConstUnsafePointer<()>, inDataSize: UInt32) -> OSStatus
But, if I change CConstVoidPointer to ConstUnsafePointer<()> I get the error:
'inout AUSamplerBankPresetData' is not convertible to 'ConstUnsafePointer<()>'
Anyone have any ideas? Thanks.
It doesn't appear necessary to have the intermediate pointer constant. You should be able to do this:
result = AudioUnitSetProperty(
samplerAudioUnit,
UInt32(kAUSamplerProperty_LoadPresetFromBank),
UInt32(kAudioUnitScope_Global),
0,
&bpData,
8)
The func has this definition:
func AudioUnitSetProperty(
inUnit: AudioUnit,
inID: AudioUnitPropertyID,
inScope: AudioUnitScope,
inElement: AudioUnitElement,
inData: ConstUnsafePointer<()>,
inDataSize: UInt32
) -> OSStatus
This line:
inData: ConstUnsafePointer<()>,
Is translated from this C:
const void * inData,
The inData parameter is a constant pointer to anything, which is what ConstUnsafePointer<()> means. I could not try this exact code within a Core Audio app, but I have gotten similar code to work.
In beta 6, it's changed again. Thankfully, this time it looks like the solution is here to stay and doesn't involve any C.
let description = AudioComponentDescription(componentType: OSType(kAudioUnitType_MusicDevice),
componentSubType: OSType(kAudioUnitSubType_Sampler),
componentManufacturer: OSType(kAudioUnitManufacturer_Apple),
componentFlags: 0,
componentFlagsMask: 0)
let instrument = AVAudioUnitSampler(audioComponentDescription: description)
let soundBankPath = NSBundle.mainBundle().pathForResource(fileName, ofType: "sf2")
let soundBankURL = NSURL.fileURLWithPath(soundBankPath!)
var error: NSError? = nil
instrument.loadSoundBankInstrumentAtURL(soundBankURL, program: program, bankMSB: UInt8(kAUSampler_DefaultMelodicBankMSB), bankLSB: UInt8(kAUSampler_DefaultBankLSB), error: &error)
For my sf2 files, the program is usually 1 or 0. I'm not really sure what this refers to, and any help is appreciated. However, this should get you unblocked for your program with a little trial and error.