Scripting Bridge classes with Swift 3 - swift

I am trying to instantiate a SB class using Swift but it doesn't seem to work:
if let messageClass = (mail as! SBApplication).class(forScriptingClass:"outgoing message") {
let message = (messageClass as! SBObject.Type).init(properties: ["subject": "message subjects"]) as MailOutgoingMessage
mail.outgoingMessages!().add(message)
print("Subject: \(message.subject)")
print("Outgoing messages: \(mail.outgoingMessages!().count)")
}
All I get in the output is:
Subject: nil
Outgoing messages: 0
I know that I should cast the message to a MailOutgoingMessage.type and not SBObject.type but I couldn't access the init method otherwise.
Someone has experience using Scripting Bridge with Swift? Clues?

Scripting Bridge is nasty, obfuscated and broken. If you have to use SB, Tony Ingraldi wrote some helper tools for Swift users. TBH, I recommend using AppleScript-ObjC over SB simply because AppleScript at least works.
For a native Swift-AE bridge, see SwiftAutomation. I'm still working on the documentation, but the code itself descends from appscript which is the only AppleScript alternative of the last 20 years that actually works right, so is just about beta-quality now.
Swift (and AppleScript) users who'd like to see Apple adopt SwiftAutomation in 10.3 are strongly encouraged to submit duplicate Radar tickets to bugreport.apple.com requesting it, e.g. here's one already copied to OpenRadar if you want to copy-paste it as-is (include the original rdar:// to help the Radar team resolve it quicker): openradar.appspot.com/29332915

Related

Detecting if Mac has a backlit keyboard

It’s quite easy to detect if Mac has an illuminated keyboard with ioreg at the command line:
ioreg -c IOResources -d 3 | grep '"KeyboardBacklight" =' | sed 's/^.*= //g'
But how can I programmatically get this IOKit boolean property using the latest Swift? I’m looking for some sample code.
I figured out the following with some trial and error:
Get the "IOResources" node from the IO registry.
Get the "KeyboardBacklight" property from that node.
(Conditionally) convert the property value to a boolean.
I have tested this on an MacBook Air (with keyboard backlight) and on an iMac (without keyboard backlight), and it produced the correct result in both cases.
import Foundation
import IOKit
func keyboardHasBacklight() -> Bool {
let port: mach_port_t
if #available(macOS 12.0, *) {
port = kIOMainPortDefault // New name as of macOS 12
} else {
port = kIOMasterPortDefault // Old name up to macOS 11
}
let service = IOServiceGetMatchingService(port, IOServiceMatching(kIOResourcesClass))
guard service != IO_OBJECT_NULL else {
// Could not read IO registry node. You have to decide whether
// to treat this as a fatal error or not.
return false
}
guard let cfProp = IORegistryEntryCreateCFProperty(service, "KeyboardBacklight" as CFString,
kCFAllocatorDefault, 0)?.takeRetainedValue(),
let hasBacklight = cfProp as? Bool
else {
// "KeyboardBacklight" property not present, or not a boolean.
// This happens on Macs without keyboard backlight.
return false
}
// Successfully read boolean "KeyboardBacklight" property:
return hasBacklight
}
As an addendum to Martin’s excellent answer, here are the notes I got from Apple’s Developer Technical Support:
Calling I/O Kit from Swift is somewhat challenging. You have
two strategies here:
You can wrap the I/O Kit API in a Swift-friendly wrapper and then use that to accomplish your task.
You can just go straight to your task, resulting in lots of ugly low-level Swift.
Pulling random properties out of the I/O Registry is not the best path
to long-term binary compatibility. Our general policy here is that we
only support properties that have symbolic constants defined in the
headers (most notably IOKitKeys.h, but there are a bunch of others).
KeyboardBacklight has no symbolic constant and thus isn’t supported.
Make sure you code defensively. This property might go away, change
meaning, change its type, and so on. Your code must behave reasonable
in all such scenarios.
Please make sure you file an enhancement request for a proper API to
get this info, making sure to include a high-level description of your
overall goal.

Crash inside http_client constructor (Casablanca SDK)

I'm trying to use Casablanca to consume a REST api.
I've been following the microsoft tutorial, how ever i'm getting a crash and I cannot figure it out.
I'm using visual studio 2017 with C++11
I've codded a function GetRequest() that do work when used in a new empty project, but when I try to use it on my Project (Very big project with millions of code lines).
I'm crashing in the constructor of http_client, in the file xmemory0 line 118.
const uintptr_t _Ptr_container = _Ptr_user[-1];
This is a link to the callstack : https://i.imgur.com/lBm0Hv7.png
void RestManager::GetRequest()
{
auto fileStream = std::make_shared<ostream>();
// Open stream to output file.
pplx::task<void> requestTask = fstream::open_ostream(U("results.html")).then([=](ostream outFile)
{
*fileStream = outFile;
// Create http_client to send the request.
http_client client(U("XXX/XXX.svc/"));
// Build request URI and start the request.
uri_builder builder(U("/IsLive"));
builder.append_query(U("q"), U("cpprestsdk github"));
return client.request(methods::GET, builder.to_string());
})
// Handle response headers arriving.
.then([=](http_response response)
{
printf("Received response status code:%u\n", response.status_code());
// Write response body into the file.
return response.body().read_to_end(fileStream->streambuf());
})
// Close the file stream.
.then([=](size_t)
{
return fileStream->close();
});
// Wait for all the outstanding I/O to complete and handle any exceptions
try
{
requestTask.wait();
}
catch (const std::exception &e)
{
printf("Error exception:%s\n", e.what());
}
}
EDIT : I just want to add that the http_client constructor is the issue. It always crash inside it no matter what I send as parameter.
The wierd thing is that it's not crashing when i just make a main() that call this function.
I guess it must be due to some memory issues, however I have no idea how could I debug that.
Does anyone would have an idea about it?
Thanks and have a great day!
I've experienced a similar issue on ubuntu. It works in an empty project, but crashes randomly when put into an existing large project, complaining memory corruptions.
Turns out that the existing project loaded a proprietary library, which is using cpprestsdk (casablanca) internally. Even cpprestsdk is static linked, its symbols are still exported as Weak Symbols. So either my code crashes, or the proprietary library crashes.
Ideally, my project can be divided into several libraries, and load them with RTLD_LOCAL to avoid symbol clashes. But the proprietary library in my project only accept RTLD_GLOBAL, otherwise it crashes... So the import order and flags become important:
dlopen("my-lib-uses-cpprest", RTLD_LOCAL); //To avoid polluting the global
dlopen("proprietary-lib-with-built-in-cpprest", RTLD_GLOBAL); //In my case, this lib must be global
dlopen("another-lib-uses-cpprest", RTLD_DEEPBIND); //To avoid being affected by global
"it will probably never concern anyone."
I agree with that.
I guess this issues was very specific, and it will probably never concern anyone, but still I'm going to update on everything I found out about it.
On this project, we are using custom allocator, if i'm not wrong, it's not possible to give our custom allocator to this lib, which result to many random crash.
A good option to fix it would be to use the static version to this lib, however, since we are using a lot of dynamic lib, this option wasn't possible for us.
If you are on my case, I would advice to use the libcurl and rapidjson, it's a bit harder to use, but you can achieve the same goal.

How to print out the method name and line number in swift

Here is an example of what I want to do:
func application(application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: NSError)
{
let nm = NetworkModel()
nm.sendlog("file name :AppDelegate , line number : 288", info: " Failed to register: \(error)")
}
current scenario i done that hard coded value line number and file name . but is it possible to programatically pick line number and file name .
Literal Type Value
#file String The name of the file in which it appears.
#line Int The line number on which it appears.
#column Int The column number in which it begins.
#function String The name of the declaration in which it appears.
#dsohandle UnsafeMutablePointer The dso handle.
Example
print("Function: \(#function), line: \(#line)")
With default values in parameters you can also create a function
public func track(_ message: String, file: String = #file, function: String = #function, line: Int = #line ) {
print("\(message) called from \(function) \(file):\(line)")
}
which can be used like this
track("enters app")
In Swift 2.1
Literal Type Value
__FILE__ String The name of the file in which it appears.
__LINE__ Int The line number on which it appears.
__COLUMN__ Int The column number in which it begins.
__FUNCTION__ String The name of the declaration in which it appears.
for more info see the documentation
You can use #function, #file, #line
Here is the implementation of log method in swift : https://github.com/InderKumarRathore/SwiftLog
Below is the snippet
public func debugLog(object: Any, functionName: String = #function, fileName: String = #file, lineNumber: Int = #line) {
#if DEBUG
let className = (fileName as NSString).lastPathComponent
print("<\(className)> \(functionName) [#\(lineNumber)]| \(object)\n")
#endif
}
For swift 4 and swift 5:
func printLog(_ message: String, file: String = #file, function: String = #function, line: Int = #line) {
#if DEVELOPMENT
let className = file.components(separatedBy: "/").last
print(" ❌ Error ----> File: \(className ?? ""), Function: \(function), Line: \(line), Message: \(message)")
#endif
}
// "❌ Error ----> File: classNameViewController.swift, function: functionName(), Line: 123, Message: messageError"
Example Logging Code (TL;DR)
import os.log
#available(OSX 11.0, iOS 14.0, *)
extension Logger {
private static var subsystem = Bundle.main.bundleIdentifier!
/// Logs the payment flows like Apple Pay.
#available(OSX 11.0, iOS 14.0, *)
static let payments = Logger(subsystem: subsystem, category: "payments")
}
static func DLog(message: StaticString, file: StaticString = #file, function: StaticString = #function, line: UInt = #line, column: UInt = #column, category: String, type: OSLogType = .info, bundle: Bundle = .main) {
// This method is only for iOS 14+
if #available(OSX 11.0, iOS 14.0, *) {
Logger.payments.debug("\(file) : \(function) : \(line) : \(column) - \(message, privacy: .private)")
// This makes the message unreadable without a debugger attached.
} else {
// Fallback on earlier versions
let customLog = OSLog(subsystem: bundle.bundleIdentifier!,
category: category)
// IMPORTANT: I have assumed here that you only print out non-sensitive data! Using %{private}# or %{public}# in an interpolated string is not portable to `Logger`!
os_log(message, log: customLog, type: type)
// Unfortunately this legacy API doesn't support non-StaticString logs. :(
}
}
Note that you may need to rework this code for more flexibility over private/public access levels - os_log and Logger don’t handle privacy levels in the same way. This is just to show how to use the API if you don’t add os_log privacy levels in message.
Apple recommend using OS Logging which is why I have used this approach rather than print statements. I added this answer because of the new Logger API in iOS 14 that also enables string interpolation.
Motivation
I think the answers here solve the question for < iOS 14, but they can be improved further for memory efficiency since this Debug Logging function will likely be used all across a codebase in iOS 14+ (new Logger API). Apple recommend using OS Logging which is why I have used this approach rather than print statements (although these will still work).
These are minor improvements but I think they can help because even minor improvements add up. In fact, the Swift Standard Library uses these optimizations everywhere they can)! These optimisations are contributing factors to the incredible memory efficiency of Swift despite being a high-level language (and part of great API Design!). (-:
Because this function would probably fit well as part of a generalized (OS) Logging service, I have also included considerations I make when logging within apps. I think these could help you when logging for debugging purposes (I answered this question because it was probably for debug logging!).
Improvements
I prefer to use UInt in certain situations if I know the Int is going to be positive, and any edge case crashes are unlikely. Note, I don't use UInt when interfacing with Foundation classes that use Int types for this reason. This allocates less memory at runtime and I find being more specific also helps me understand the code better.
I prefer to use StaticString where I know the string is known at compile-time. From the docs, StaticString only provides low-level access to String contents and is immutable. Thus only use it where appropriate. Even concatenated String literals cannot be used to initialize a StaticString. Because its functionality is more restricted than String this means that it is lightweight - only requiring an address pointer and length under the hood. Using StaticString also provides a small performance boost with OS-level memory management because it is neither allocated nor deallocated (no need for reference counting).
Using Apple's recommended Logger API for logging is better than print statements for multiple reasons: performance, privacy and unified management. It can be better for debugging issues in released products (OS Logs provide more context).
I would recommend using StaticString where you can, for example with the function and file names, and UInt for the line and column numbers. This is only now possible with the Logger iOS 14+ API.
(Bonus) Logging Considerations
Should I do LOTS of logging?
I think logging is a balancing act. Lots of logging can be very helpful to debug issues when viewing crash reports if you have access to these. However, you need to balance Privacy, Size of the Compiled Binary and Overwhelming the Logging System.
1. Privacy: Redact sensitive info using "\(message, privacy: .private)" and "\(message, privacy: .public)" with Logger, and DON'T print sensitive information when using NSLog or print statements. I would recommend replacing print statements (for production) with OS Logs when they are for debugging purposes. Or use a preprocessor directive (#if DEBUG) inside the logging service to print only on a Debug scheme..
2. Size of the Compiled Binary: Logging statements are essentially more lines of code. The more code you add, the bigger your binary. This is usually not an issue, as long as you don't log everything under the sun since only a large increase in this metric would affect the binary size.
3. Overwhelming the logging system: If you log excessively, the device may have to discard some logs in order to keep running (limited RAM or swap space at runtime due to OS multitasking - worse for older devices). Apple is usually reliable in handling lots of user logging, and it's hard to achieve this in practice. Nevertheless, if you do encounter this, some more useful log events could be pushed out of the window.
OS Logs
The most important thing to get right is the log level. By default on iOS log entries at .info and below will be suppressed at the point of log generation, so the only real negative with those is the binary size. If you log at .log (.default for os_log) or higher, you need to be careful about not logging too much. Apple's general advice is that you look at each of these higher-level log entries to make sure they contain info that might be useful while debugging.
Finally, make sure to set the subsystem and category. The unified logging system processes a lot of log entries - the subsystem with category makes it much easier for you to focus on specific problems.
How to choose the category and subsystem?
This is a pretty opinionated topic, so I will focus on what I would think about when deciding. YMMV: there may be better options and if so, please let me know.
1. By feature (product-specific): For example, if you are a shopping app, maybe organise the subsystem by the payment, login or other app flows. If you aren't already using a modular codebase for organisation into features (or frameworks for shared code) then I can recommend this tutorial series.
2. By technology: What I mean by this is the domain of the code, is it for Push Notifications, Deep Links, User Defaults (or persistence) logic. This could be helpful for the category parameter.
3. By target: I like to also use the bundleIdentifier of the current Bundle if I can for the subsystem. This makes even more sense if you have Extension Targets (Push Notifications), multiple Targets, or different Platforms (like WatchOS, SiriKit extensions and similar). You can get the current bundle, using this code:
let myBundle = Bundle(for: MyClass.self)
Debugging user issues using OS device logs
See here for a detailed walkthrough (Access Device Console Logs). The main idea is to connect the device to your Mac (or use the Mac itself for Mac apps ;)), open Console.app, run the app and try to reproduce the crash. If you manage to get that far in the first place, then you can correlate the time of the crash with the logs for more context.
Any other reasons for logging less?
If you are an Apple Early-Adopter then you know how buggy some of the iOS Betas can be ;). When posting bug reports to Apple, the OS Logs get included in sysdiagnose files, so you may get a faster turnaround time because your bug reports have less noise.
Should I use a third-party logging service?
Depends if you can afford it and whether you really need it. I prefer to minimise the number of third-party dependencies I import in my code (if I can control this) and the native (Apple) Logging APIs worked fine for most of my use cases. These services charge extra per month, but the advantage is the user cannot view the logs (even if he wants to) by hooking his device up to Console.app on his Mac. Note that this is NOT an issue if you apply the .private log levels, so I don't usually use third-party services (YMMV). A potential reason to go for web-logging is more security against reverse-engineering though, as long as you trust the third-party vendor against data breaches (BUT also it's not as eco-friendly ;)).
static func DLog(message: String, file: String = #file, function: String = #function, line: Int = #line, column: Int = #column) {
print("\(file) : \(function) : \(line) : \(column) - \(message)")
}
add where ever you want in your code (inside a struct/var/closure/func...) the next line:
let _ = print("**** \(#file)" + String(describing: type(of: self)) + ".\(#function)[\(#line)]")
and it will print the next line:
**** /path/to/my/file.swift MyClass.someFunc()[17]

Xcode 8 random command failed due to signal segmentation fault 11

I have a strange problem with the new Xcode 8 (no beta version) and swift3.
Once every other 3-4 times that I compile my code I get a 'command failed due to signal segmentation fault 11' error. I just need to enter new empty line, or sometimes changing some spaces, or add a comment (everywhere in the code) and the error disappears and I can compile again.
This is really strange because I'm not changing anything in the code! And sometimes I can compile and it works, then I don't change anything, I compile again and I get the error.
This is really annoying!
I have noticed this is happening since I have installed several 'Firebase' pods (Firebase, Firebase/Auth etc...). But I need them.
Anyone has any suggestion?
PS: I have set the Enable Bitcode of my project to No as many solution suggested, but nothing. In the error message it is not indicated any swift page where the error can be, an example is:
While loading members for 'Class_name' at
While deserializing 'func_name' (FuncDecl #42)
'func_name' is this one:
public class func loginUser(fir_user: FIRUser) {
let user = SFUser()
user.email = fir_user.email
user.isLogged = true
try! sfRealm.write() {
sfRealm.add(user, update:true)
}
var userToAdd = [String:AnyObject]()
userToAdd["email"] = fir_user.email! as NSString
let ref=FIRDatabase.database().reference()
let usersRef = ref.child(childName)
usersRef.setValue([key:value])
}
But then, as I said, I can just enter an empty row in another file and it compiles!
Thanks
I have the same issue i just figure out that i was using xcode 8.1 and the project's working copy was in xcode 8.2.1 so i just re install xcode 8.2.1 and problem got solved. Hope other can get the help trough this.
Ok, it seems that I have found the solution: it is a problem with Firebase and cocoapods, so 2 solutions:
Download Firebase and import into your project
I, instead, updated cocoapods to the last version and it worked. Upgraded Firebase - Now Getting Swift Compile Error
In my case there was some type checking issue deep down the compiler so the editor didn't give error in the gutter but on building the project I was getting signal setmentation fault 11 error:
1. While type-checking 'GetStoreAPIRequestModel' at /Users/.../StoreAPIModel.swift:9:1
2. While type-checking expression at [/Users/.../StoreAPIModel.swift:15:18 - line:15:31] RangeText="[Dictionary]()"
3. While resolving type [Dictionary] at [/Users/.../StoreAPIModel.swift:15:18 - line:15:29] RangeText="[Dictionary]"
So I changed my code from:
var stores = [Dictionary]() {
willSet {
allStores.removeAll()
for model in newValue {
allStores.append(StoreAPIModel(dictionary: model as! Dictionary).getModel())
}
}
}
To (more descriptive dictionary):
var stores = [[String : Any]]() {
willSet {
allStores.removeAll()
for model in newValue {
allStores.append(StoreAPIModel(dictionary: model as [String : AnyObject]).getModel())
}
}
}
This is tricky problem. Issue can be with line of code or syntax. I was getting similar error and it was due to incorrect usage of dictionary. I was trying to increment the value of dictionary element.
Solution is to triage the code, detailed error provide which module has issue, so try commenting part of code until you find the line which is causing the issue.
Hi i had the same issue with FireBase , my problem was that i was extending FIRStorageReference and FIRDatabaseReference and some time it compile successfully some time i get
command failed due to signal segmentation fault 11
so i removed that files and implement the method other way , now everything works fine.
Found my problem when this occurred. (No cocoapods.) I thought I had left the program in a working state, but I was wrong. I am writing a straightforward command-line program. What it does is somewhat general, so I defined all the strings that make it specific in let statements at the top of the program so that I could someday use the program in a different context.
Since that was working so well, I thought I'd be clever and do the same with a filter of an array of dictionaries. I turned:
list.filter { $0["SearchStrings"] == nil }
into:
let test = { $0["SearchStrings"] == nil }
// ...
list.filter(test)
meaning to continue working on the let, but I never went back and did that. Building gave me the segmentation fault error. Defining test as a function fixed the problem.
(Incidentally, I understand how to strip a filtering function down to the terse braces notation in the context of the call to Array.filter, and why that works, but I don't understand why I can't assign the brace expression to a constant and use it as such.)

How do I detect if XenApp Client is installed on user machine?

We are upgrading from Citrix Metaframe to XenApp, and I need to know if there's a way to programmatically detect if the XenApp Web Plugin v11.0 is already installed on a client machine when it contacts our webserver for login -- this was previously done for the Metaframe Web Client by attempting to instantiate the ICA client in an ASP script, which used the results to determine whether to offer the client as a download/install.
The current code for this detection is:
Set icaObj = CreateObject("Citrix.ICAClient")
The above code does not find the XenApp plugin.
I continued my research after posting this question and I finally found the answer. Only 3 views on this question since I posted it, but despite the disinterest I believe I should answer my question, "Just in Case" someone else has this problem.
I was mistaken in my statement in question that the code I posted didn't find the XenApp plugin. In fact, it does. It returns a valid object in the presence of both Metaframe and XenAppWeb. I posted this question on Citrix's own forums, and no answers there either.
What I did to find the answer was to create a VS2008 project to which I added a COM reference to the Citrix ICA library -- both of them, installed separately one at a time. I found that both had a COM library named WFICALib, and searched through both of them to see if there was something that might distinguish them. What I found was a property, ClientVersion, which was 9.0.xxx for Metaframe, and 11.0.xxxx for XenAppWeb.
BINGO!
From this I cut the following code to return the version as a function in VBScript:
Function GetVer()
Dim icaObj, Ver
On Error Resume Next
Set icaObj = CreateObject("Citrix.ICAClient")
if err.number = 0 then
if IsObject(icaObj) then
GetVer = icaObj.ClientVersion
else
GetVer = 0
end if
set icaObj = nothing
else
GetVer = 0
end if
End Function
ADDENDUM:
Since posting this answer, I have discovered that this script in the newer versions of Internet Explorer (e.g. IE9) is not reliably detecting the plugin -- sometimes it worked, and other times not! What I did to fix the problem was to switch the script to JScript instead of JavaScript, and the new version looks like this:
<script type="text/jscript">
function GetCitrixVersion() {
try {
var icaObj = new ActiveXObject("Citrix.ICAClient");
return icaObj.ClientVersion;
}
catch (e) {
return 0;
}
}
</script>
Note the script type is text/jscript, not text/javascript.