This problem came up trying to run macOS commands within a swift file. I'm having some issues passing arguments into functions using Swift. When I run the lines within the function date outside of the function definition, things work just fine. I'm not able to see any errors within Xcode. As a Swift newbie, any advise is appreciated!
import Foundation
import Cocoa
//Command arguments
let dateLocation = "/bin/date"
let format = "+DATE: %Y-%m-%d%nTIME: %H:%M:%S"
let command = Process()
//Command function with arguments
func date(args: String) -> String {
command.executableURL = URL(fileURLWithPath: dateLocation)
command.arguments = [args]
try command.run()
}
//Run function
date(args: format)
First of all your function is declared to return a string but doesn't return anything and secondly you are calling a function that can throw an error which you correctly handles by using try but you need to either handle any possible error or throw it from your function. Here I chosed the later in my example by adding throws to the declaration
func date(args: String) throws {
command.executableURL = URL(fileURLWithPath: dateLocation)
command.arguments = [args]
try command.run()
}
Now you can call your function and catch any error like below
do {
try date(args: format)
} catch {
print(error)
}
Output:
DATE: 2020-03-31
TIME: 18:50:25
Related
I'm learning SpriteKit, and trying to create a simple dictionary, that is, this simple dictionary:
class GameScene: SKScene {
let someDic = ["a":1, "b":2, "c":3]
print(someDic)
I constantly end up with the following error message:
Cannot find type 'someDic' in scope
What am I doing wrong?
The code you posted won't compile. The print statement has to be inside a function.
I would expect the error "Expected 'func' keyword in instance method declaration".
If you create a command line tool, this code WOULD compile and run:
import Foundation
class Foo {
let someDic = ["a":1, "b":2, "c":3]
func someFunc() {
print(someDic)
}
}
let aFoo = Foo()
aFoo.someFunc()
I can't figure out why I keep getting the Swift warning: Use of unresolved identifier 'Functions on this line of my code: let functions = Functions.functions()
My imports for the viewController includes import Firebase and it works fine when I declare let db = Firestore.firestore() right above the line let functions = Functions.functions()
My podfile includes pod 'Firebase/Functions' and I've installed the pod.
I'm calling functions later using the following code and when I type "functions" it recommends adding .httpsCallable which leads me to believe that it actually does recognize the object "functions":
func getData(){
functions.httpsCallable("helloWorld").call(userData) { (result, error) in
if let error = error {
print(error)
}
if let data = result?.data {
print(data)
}
}
}
Figured it out. Importing Firebase is not enough, one must also import FirebaseFunctions (despite what Swift thinks, see screenshot below).
I have a class that contains some Alamofire code to get JSON from a server, convert it into a pre-defined model and then return that model as an array.
Here is the code
func GetLights(completionHandler: #escaping (DataResponse<[LightList]>) -> Void) -> Alamofire.DataRequest {
return AF.request(APIString + "/lights").responseJSON { response in
let LightListResponse = response.flatMap { json in
try JSONDecoder().decode([LightList].self, from: response.data!)
}
completionHandler(LightListResponse)
}
}
func GetLightList() {
GetLights { response in
if let lights = response.value {
print(lights)
}
}
}
I can breakpoint through to the JSONDecoder and see the json via debug but the print line at the end prints nothing, it doesn't even hit a breakpoint.
Can anyone see what I'm doing wrong? I think I'm using the completion handler correctly?
I am calling the GetLightList via a SwiftUI file like so:
func InitList() {
let requests = Requests()
requests.GetLightList()
}
You shouldn't be doing this using responseJSON, as that method has already parsed the JSON using JSONSerialization and made it available to you as part of the response. Instead, you should use responseDecodable, since you already have a Decodable type.
return AF.request(apiString + "/lights").responseDecodable(of: [LightList].self) { response in
completionHandler(response)
}
However, it's often best not to expose the DataResponse type produced by Alamofire but instead use the Result from the response in your completion handler.
Additionally, updating your styling to match Swift's recommended style will help you write consistent code. Namely, methods and variable names should start with a lowercase letter to separate them from type declarations. You can see this in your code samples where it thinks things like "APIString" are types and not variables.
Finally, it's often helpful to not overload get as a method prefix. For network calls I like using fetch when requesting a resource. e.g. fetchLights.
I am writing some Swift code and I would like to know the class of the object that called the function. I don't want to pass in any parameters. From within the function I want to be able to know who called it.
Any suggestion?
If you want to do that using Swift, you can do this:
func debug(file: String = #file, line: Int = #line, function: String = #function) -> String {
return "\(file):\(line) : \(function)"
}
To access the underlying class of a method from within itself, use the dynamicType property:
self.dynamicType
If you want to know the origin of the original call, you can use NSThread to return debugging information about the stack:
NSThread.callStackSymbols()
This method returns a descriptive array of values that you're used to seeing when exceptions are thrown. The strings represent a backtrace of all current activity on your call stack.
I don't want to be presumptuous, but it seems to me that outside of debugging, there isn't a good reason, conceptually, at least, to know the origin of a specific method call for any and every function. If you need to retrieve the class Type of the last method call on the stack, why not implement an interface that lets you access this information through a straightforward route?
You can use following template to know from which file, line number in file, and function this someFunction is called:
func someFunction(file: String = #file, line: Int = #line, function: String = #function)
{
NSLog("\(file.lastPathComponent):\(line) : \(function)")
}
Swift:
Add a (sender: Anyobject) as parameter to that function, and then print the sender (the function caller) like this:
func yourFunc(sender: AnyObject){
print(sender)
}
Or add a symbolic breakpoint with a po thread to see the stack trace of the caller of the method
The final way, use the follow protocol:
protocol PrefixPrint {
func formatPrint(_ text: String, function: String, line: Int) -> Void
}
extension PrefixPrint {
#inline(__always)
func formatPrint(_ text: String, function: String = #function, line: Int = #line) {
#if DEBUG
print("\(self).\(function).\(line): \(text)")
#endif
}
}
Console like: FootBall.VNSocketManager.init().44: xx
Joining together a couple of answers and comments:
func function(file: String = #file) {
if let url = URL(string: file) {
let className = url.deletingPathExtension().lastPathComponent
print(className)
}
}
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