I have a macOS app in swift that crashes only when archived (not run from XCode).
It crashes on the following code:
private static func myFunc(originalValue: String) {
DLog("Starting myFunc on: '\(originalValue)'") // CRASHES when app is exported
}
Here is the DLog function (when exported, the DEBUG flag is not set, so it will not execute the NSLog):
func DLog(_ message: String, function: String = #function) {
#if DEBUG
NSLog("%#, %#", function, message)
#endif
}
The originalValue that makes the app crash is a String containing basic characters (letters or numbers), no %# or other format string stuff.
Now the funniest part, if I print (using Swift.print) originalValue before calling DLog, it won't crash:
private static func myFunc(originalValue: String) {
print("Starting myFunc on: '\(originalValue)'") // prevents the crash
DLog("Starting myFunc on: '\(originalValue)'") // DOES NOT crash because of the print before
}
Any logical explanation to this strange behavior?
Thanks!
Related
TL;DR I'm attempting to convert UnsafeMutableRawPointer into some UnsafePointer<T>.
I've developed a Minimal Reproducible Example of my program (Here's a snippet)
var foo: Int = 100
var bar: String = "hello"
func unsafe(_ mutable: (UnsafeMutableRawPointer...) -> ()) {
mutable(&foo, &bar)
}
unsafe { (mutable: UnsafeMutableRawPointer...) in
for m in mutable {
print(UnsafePointer<Int>(.init(m)).pointee)
}
}
The goal is to print this...
100
"hello"
Instead, here is what was printed...
100
478560413032
Finally, if I try and replace...
print(UnsafePointer<Int>(.init(m)).pointee)
with...
print(UnsafePointer<String>(.init(m)).pointee)
I also receive a crash. (If this could be handled with try that would be great. But it is not a throwing method.)
I really wish this was possible, but unfortunately this also crashes:
print(UnsafePointer<Any>(.init(m)).pointee)
I have a very simple code, but when I call testFunc() it crashes on line value = NSObject() with error EXC_BAD_ACCESS (code=EXC_I386_GPFLT). Could anyone explain, why does it happens?
class A {
var object: Any?
convenience init() {
self.init(nil)
}
private init(_ object: Any?) {
self.object = object
}
}
class B: A {
var value: Any?
func test() {
value = NSObject()
}
}
func testFunc() {
let b = B()
b.test()
}
If I run your code in a Mac command line tool, it works just fine. If I run it as an iOS playground, it crashes.
It looks like a bug in playgrounds to me. (It wouldn't be the first time. I find playgrounds pretty unstable, and tend to test out non-UI coding ideas with command line tools rather than playgrounds because I find playgrounds to be flaky and unreliable.)
I tried adding print statements at various points, and the first time I added a print statement it didn't crash. Then several edit/run cycles later, it didn't crash again. I don't see anything wrong with your code (other than the fact that it doesn't really do anything, and there's no real point in creating an empty NSObject.)
I am trying to create a generic function that can take an optional argument.
Here's what I have so far:
func somethingGeneric<T>(input: T?) {
if (input != nil) {
print(input!);
}
}
somethingGeneric("Hello, World!") // Hello, World!
somethingGeneric(nil) // Errors!
It works with a String as shown, but not with nil.
Using it with nil gives the following two errors:
error: cannot invoke 'somethingGeneric' with an argument list of type '(_?)'
note: expected an argument list of type '(T?)'
What am I doing wrong and how should I correctly declare/use this function? Also, I want to keep the usage of the function as simple as possible (I don't want do something like nil as String?).
I guess the compiler can't figure out what T is just from nil.
The following works just fine though for example:
somethingGeneric(Optional<String>.None)
I believe you've overcomplicated the problem by requiring the ability to pass untyped nil (which doesn't really exist; even nil has a type). While the approach in your answer seems to work, it allows for the creation of ?? types due to Optional promotion. You often get lucky and that works, but I've seen it blow up in really frustrating ways and the wrong function is called. The problem is that String can be implicitly promoted to String? and String? can be implicitly promoted to String??. When ?? shows up implicitly, confusion almost always follows.
As MartinR points out, your approach is not very intuitive about which version gets called. UnsafePointer is also NilLiteralConvertible. So it's tricky to reason about which function will be called. "Tricky to reason about" makes it a likely source of confusing bugs.
The only time your problem exists is when you pass a literal nil. As #Valentin notes, if you pass a variable that happens to be nil, there is no issue; you don't need a special case. Why force the caller to pass an untyped nil? Just have the caller pass nothing.
I'm assuming that somethingGeneric does something actually interesting in the case that it is passed nil. If that's not the case; if the code you're showing is indicative of the real function (i.e. everything is wrapping in an if (input != nil) check), then this is a non-issue. Just don't call somethingGeneric(nil); it's a provable no-op. Just delete the line of code. But I'll assume there's some "other work."
func somethingGeneric<T>(input: T?) {
somethingGeneric() // Call the base form
if (input != nil) {
print(input!);
}
}
func somethingGeneric() {
// Things you do either way
}
somethingGeneric(input: "Hello, World!") // Hello, World!
somethingGeneric() // Nothing
Good question and answer. I have an Swift 4 update to contribute:
var str: String? = "Hello, playground"
var list: Array<String>? = ["Hello", "Coder256"]
func somethingGeneric<T>(_ input: T?) {
if (input != nil) {
print(input!);
}
}
func somethingGeneric(_ input: ExpressibleByNilLiteral?) {}
somethingGeneric("Hello, World!") // Hello, World!
somethingGeneric(nil) // *nothing printed*
somethingGeneric(nil as String?) // *nothing printed*
somethingGeneric(str) // Hello, playground
str = nil
somethingGeneric(str) // *nothing printed*
somethingGeneric(list) // ["Hello", "Coder256"]
list = nil
somethingGeneric(list) // *nothing printed*
I figured it out:
func somethingGeneric<T>(input: T?) {
if (input != nil) {
print(input!);
}
}
func somethingGeneric(input: NilLiteralConvertible?) {}
somethingGeneric("Hello, World!") // Hello, World!
somethingGeneric(nil) // *nothing printed*
somethingGeneric(nil as String?) // *nothing printed*
I think that you will never call somethingGeneric(nil) but mostly somethingGeneric(value) or somethingGeneric(function()) for which the compiler has enough info not to be stucked trying to guess the type:
func somethingGeneric<T>(input: T?) {
if let input = input {
print(input);
}
}
func neverString() -> String? {
return nil
}
let a: String? = nil
somethingGeneric("Hello, World!") // Hello, World!
somethingGeneric(a) // Nothing and no error
somethingGeneric(neverString()) // Nothing and no error
Also, I would use the if let syntax instead of if(value != nil).
Here is the solution I came up with that compiles on Swift 5, as many of the solutions here did not compile for me. It might be considered hacky as I use a stored variable to help things along. I was unable to come up with a Swift 5 version of the nil parameters that resolve to type T.
class MyClass {
func somethingGeneric<T>(input: T?) {
if let input = input {
print(input)
}
}
func somethingGeneric() {
somethingGeneric(Object.Nil)
}
}
final class Object {
static var Nil: Object? //this should never be set
}
Actually there is a way to do this, inspired by Alamofire's internal code.
You do not have to install Alamofire to use this solution.
Usage
Your problematic method definition
func someMethod<SomeGenericOptionalCodableType: Codable>(with someParam: SomeGenericOptionalCodableType? = nil) {
// your awesome code goes here
}
What works ✅
// invoke `someMethod` correctly
let someGoodParam1 = Alamofire.Empty.value
someMethod(with: someGoodParam1)
I think it is possible to use Alamofire.Empty.value as a default value in someMethod definition as a parameter.
What does not work ❌
// invoke `someMethod` incorrectly
let someBadParam1: Codable? = nil
let someBadParam2 = nil
someMethod(with: someBadParam1)
someMethod(with: someBadParam2)
Solution definition (source)
/// Type representing an empty value. Use `Empty.value` to get the static instance.
public struct Empty: Codable {
/// Static `Empty` instance used for all `Empty` responses.
public static let value = Empty()
}
I have a Log function I use in various apps. Its convenient for this to also make Crashlytics logging calls since I use it throughout the app.
However, not every app uses Crashlytics. In Objective C you could handle this with preprocessor conditions.
How would one handle this in code? I think there are ways to make the function conditional perhaps. But how would I optionally or weak import Crashlytics?
import Foundation
//import Crashlytics
/// Debug Log: Log useful information while automatically hiding after release.
func DLog<T>(message: T, filename: String = __FILE__, function: String = __FUNCTION__, line: Int = __LINE__) {
// CLSLogv("\(NSString(string: filename).lastPathComponent).\(function) line \(line) $ \(message)", getVaList([]))
print("[\(NSString(string: filename).lastPathComponent) \(function) L\(line)] \(message)")
}
You can do this now in Swift 4.1 with the new canImport() directive. This is the Swift Evolution proposal that describes how it works: https://github.com/apple/swift-evolution/blob/master/proposals/0075-import-test.md
So you could do:
#if canImport(Crashlytics)
func dLog() {
// use Crashlytics symbols
}
#endif
I would do it a different way in Swift. I would make my log function extensible. I would have an array of log closures that do actual logging and my dlog function would invoke all of them e.g.
private var logFunctions: [(String) -> ()] = [ { print($0) } ]
func dlog(message: String, filename: String = __FILE__, function: String = __FUNCTION__, line: Int = __LINE__)
{
let logMessage = "[\(NSString(string: filename).lastPathComponent) \(function) L\(line)] \(message)"
for log in logFunctions
{
log(logMessage)
}
}
dlog("Hi", filename: "file", function: "function", line: 1)
print("---")
logFunctions.append{ print("New print: " + $0) }
dlog("Hi", filename: "file", function: "function", line: 2)
Output is
[file function L1] Hi
---
[file function L2] Hi
New print: [file function L2] Hi
So in any application that supports Crashlytics, in your application start up code, you add the crashlytics logger to your array of loggers i.e.
import Crashlytics // Only needed in the Swift file with app start up code
// ...
logFunctions.append{ CLSLogv($0, getVaList([])) }
Of course you should encapsulate all of the above in a class or something.
This is possible in Swift even though the Swift compiler does not include a preprocessor.
import Foundation
#ifdef DEBUG
import Crashlytics
#endif
/// Debug Log: Log useful information while automatically hiding after release.
func DLog<T>(message: T, filename: String = __FILE__, function: String = __FUNCTION__, line: Int = __LINE__) {
#ifdef DEBUG
CLSLogv("\(NSString(string: filename).lastPathComponent).\(function) line \(line) $ \(message)", getVaList([]))
#else
print("[\(NSString(string: filename).lastPathComponent) \(function) L\(line)] \(message)")
#endif
}
Now, the following code is untested and MAY need some tweaking - but it can help if you want to clean up your code! #transparent will inline the body of the code, by the way.
import Foundation
#ifdef DEBUG
import Crashlytics
#transparent printfn(item: String) {
CLSLogv(item, getVaList([])
}
#else
let printfn = println
#endif
/// Debug Log: Log useful information while automatically hiding after release.
func DLog<T>(message: T, filename: String = __FILE__, function: String = __FUNCTION__, line: Int = __LINE__) {
printfn("\(NSString(string: filename).lastPathComponent).\(function) line \(line) $ \(message)")
}
Please note: you must set the "DEBUG" symbol as it is not predefined. Set it in the "Swift compiler - Custom Flags" section of the compiler, "Other Swift Flags" line. You cand efine the DEBUG symbol with the -D DEBUG entry.
Hope I was able to help!
With this code:
func externalFunc() {
println("How can I know which object/class is calling me?")
}
class Test {
func callExternalFunc() {
externalFunc()
}
}
In the Objective-C runtime objc_msgSend passes two hidden parameters to every message we send. They are self and _cmd. (Source)
In the above example, is there any way to know who is calling externalFunc?
I'm not sure if there is a way to obtain this automatically, but you can get this info if you add a default param of type String to the function and set it to #function.
For example...
func externalFunc(callingFunctionName: String = #function) {
println("Calling Function: \(callingFunctionName)")
}
Then you would call it without the added default param...
let test = Test()
test.callExternalFunc()
And it would print the following...
"Calling Function: callExternalFunc()"
If you are willing to modify the method signature you could do something like below:
func externalFunc(file: String = #file, line: Int = #line) {
print("calling File:\(file) from Line:\(line)")
}
From apple's swift blog
Swift borrows a clever feature from the D language: these identifiers
(__FILE__ & __LINE__ ) expand to the location of the caller when
evaluated in a default argument list.
Note that __FILE__ and __LINE__ have been depreciated in Swift 2.2 and have been removed in Swift 3. They are replaced by #file, and #line.
Here's a great utility class I found on github:
https://github.com/nurun/swiftcallstacktrace
Use like this:
let callingMethodInfo = CallStackAnalyser.getCallingClassAndMethodInScope(false)
if let callingMethodInfo = callingMethodInfo {
NSLog("class: %#", callingMethodInfo.0)
NSLog("method: %#", callingMethodInfo.1)
}
In your question you are mentioning self and _cmd.
self is accessible in Swift exactly in the same way as in Obj-C (which is logical).
_cmd (selector of the current method) is not accessible. There is no reason for it to be accessible, Swift doesn't use selectors outside Obj-C contexts (in pure Swift you cannot call selectors dynamically). The only use case for it is to print the name of the current function for debugging purposes. The same can be achieved in Obj-C (or C) using __FUNCTION__ macro. The same can be achieved in Swift:
func getCurrentFunctionName(functionName: StaticString = #function) -> String {
return String(functionName)
}
func externalFunc() {
print("Function name: \(getCurrentFunctionName())") // prints "externalFunc"
}
Note that in your example externalFunc is a function, not a method. Even in Obj-C neither self or _cmd wouldn't be available for it.
If you want to know who has called your method (and I really suppose you want to know it for debugging purposes), then you can inspect your call stack:
func externalFunc() {
let stackSymbols = NSThread.callStackSymbols()
stackSymbols.forEach {
let components = $0.stringByReplacingOccurrencesOfString(
"\\s+",
withString: " ",
options: .RegularExpressionSearch,
range: nil
).componentsSeparatedByString(" ")
let name = components[3]
let demangledName = _stdlib_demangleName(name)
print("\(demangledName)")
}
}
which prints (for my project called SwiftTest):
SwiftTest.externalFunc () -> ()
SwiftTest.Test.callExternalFunc () -> ()
main
start
0x0