how to use AXUIElementCopyAttributeValue from Swift? - objective-c

I am trying to use AXUIElementCopyAttributeValue from Swift. My best stab currently looks like this:
private func mainWindow() -> Optional<AXUIElementRef> {
let appRef = AXUIElementCreateApplication(self.pid())
var ptr: Unmanaged<AXUIElementRef>? = nil
var frontWindow: AXUIElementRef? = nil
let err = AXUIElementCopyAttributeValue(appRef, kAXMainWindowAttribute, &ptr)
if err == AXError(kAXErrorSuccess) {
frontWindow = ptr!.takeRetainedValue()
}
return frontWindow
}
Unfortunately kAXMainWindowAttribute is not in scope. This works in ObjC of course, but I can't figure out where the value is hiding when accessed from Swift. This isn't the first time I've had this problem, either, although previously I've been able to stumble around a bit and find it.
Also, I'd be happy to receive any stylistic suggestions here. I'm not convinced I'm doing this in the most natural way for Swift.

It is an old question but I still drop it here in case someone else searches for it:
let appRef = AXUIElementCreateApplication(pid)
var value: AnyObject?
AXUIElementCopyAttributeValue(appRef, kAXMainWindowAttribute as CFString, &value)
also, I assume you get the "Swift dynamic cast failed" error message because you try to cast from AXUIElement to AnyObject. You can cast it like so:
print(value as! AXUIElement)

This is not an answer yet, but perhaps might help someone get me an answer... I changed the code to this, in order to make forward progress:
func mainWindow() -> WBWindow? {
var result: WBWindow? = nil
var ptr: Unmanaged<AnyObject>?
let kAXMainWindow: CFString! = "AXMainWindow" as NSString
let appRef: AXUIElement! = AXUIElementCreateApplication(self.pid()).takeRetainedValue()
let err = AXUIElementCopyAttributeValue(appRef, kAXMainWindow, &ptr)
if err == AXError(kAXErrorSuccess) {
let val: AnyObject? = ptr?.takeRetainedValue()
if val != nil {
let value: AnyObject = val!
let description = CFCopyTypeIDDescription(CFGetTypeID(value))
println("type = \(description)")
}
else {
NSLog("got nil result")
}
// result = WBWindow(element: ptr?.takeRetainedValue() as? AXUIElement)
}
return result
}
This now builds -- yay! But, when running, the commented out line drops me into a stack:
0x1001b57ea: leaq 0x3f1a1(%rip), %rax ; "Swift dynamic cast failed"
I added the debugging code above and that produces:
type = AXUIElement
Sooooo. It's an AXUIElement that won't cast to one? Clearly I'm missing something obvious...

Related

Unable to understand the certain operator in Swift

I have been changing some SWIFT code into OBJECTIVE-C, and I am stuck at certain part of the code, where I am unable to understand if it is a condition or something else.
Following is the code and I am stuck on 9th line stating :
if let channel1Buffer = buffer.floatChannelData?[0]
What I do not understand here is the above if condition is checking if "buffer.floatChannelData" is null, and then proceeding to get the first index, or is it something else.
input.installTap(onBus: 0, bufferSize:4096, format:format, block: { [weak self] buffer, when in
guard let this = self else {
return
}
print("Buffer Float Channel Data: ", buffer.floatChannelData as Any);
**if let channel1Buffer = buffer.floatChannelData?[0]** {
print("channel1Buffer: ", channel1Buffer);
/// encode PCM to mp3
let frameLength = Int32(buffer.frameLength) / 2;
print("frameLength: ", frameLength);
let bytesWritten = lame_encode_buffer_interleaved_ieee_float(this.lame, channel1Buffer, frameLength, this.mp3buf, 4096);
// `bytesWritten` bytes stored in this.mp3buf now mp3-encoded
print("\(bytesWritten) encoded");
this.file.append(this.mp3buf, length: Int(bytesWritten));
// #TODO: send data, better to pass into separate queue for processing
}
})
Let's take it part by part - buffer.floatChannelData?[0]
buffer has property named floatChannelData which is optional so it has ? at the end. then it takes that optional which accepts subscription [0] which also returns optional value. So it continues inside {} only if floatChannelData is not nil AND it's first value is not nil
Your Objc should look like
float *const *channelData = [buffer floatChannelData];
if (channelData) {
float *channel1Buffer = channelData[0]; //this might crash if channelData is empty
...
The line tries to assign the variable channel1Buffer the value of buffer.floatChannelData[0], and the code within {} is only executed if that assignment is successful. It may for instance fail if buffer.floatChannelData is nil or buffer.floatChannelData[0] is nil.

Ambiguous use of intValue Swift3

I have been trying to convert existing swift2.3 to swift3. I got Ambiguous use on intValue error at the following code.
jobPackageVersion.intJobPackageId = (JobPackageVersionDictionary["intJobPackageId"]! as AnyObject).intValue as NSNumber
Here is the full code
if let url = Bundle.main.url(forResource: "tblJobPackageVersion", withExtension: "csv") {
do {
let strData = try String(contentsOf: url)
let csv = CSwiftV(String: strData)
if csv.keyedRows != nil {
for dictionary in csv.keyedRows! { // [Dictionary<String, String>]
let JobPackageVersionDictionary = dictionary as NSDictionary // Cast to NSDictionary
let JobPackageVersionEntity = NSEntityDescription.entity(forEntityName: "JobPackageVersion", in: context)
let jobPackageVersion = JobPackageVersion(entity: JobPackageVersionEntity!, insertInto: context)
// Set object attributes
jobPackageVersion.intJobPackageId = (JobPackageVersionDictionary["intJobPackageId"]! as AnyObject).intValue as NSNumber
jobPackageVersion.intJobPackageVersionId = (JobPackageVersionDictionary["intJobPackageVersionId"]! as AnyObject).intValue as NSNumber
jobPackageVersion.intStatus = (JobPackageVersionDictionary["intStatus"]! as AnyObject).intValue as NSNumber
jobPackageVersion.intVersion = (JobPackageVersionDictionary["intVersion"]! as AnyObject).intValue as NSNumber
do { // Save object to database and clean up memory
try context.save()
context.refresh(jobPackageVersion, mergeChanges: false)
} catch let error as NSError { Logger.sharedInstance.logMessage("\(#function) JobPackageVersion Saving Error: \(error.userInfo)") }
} // for-loop
Logger.sharedInstance.logMessage("\(#function): Loaded \(csv.keyedRows!.count) tblJobPackageVersion records.")
} else { Logger.sharedInstance.logMessage("\(#function) CSV Parser Warning: no CSV data was parsed in tblJobPackageVersion.csv!") }
} catch { Logger.sharedInstance.logMessage("\(#function) Error reading contents of tblJobPackageVersion.csv.") }
} else { Logger.sharedInstance.logMessage("\(#function) Error locating URL for resource tblJobPackageVersion.csv") }
}
Any help would be appreciated.
Thanks.
You're trying to call intValue on an object of type AnyObject. As the error states, this is too ambiguous because both NSNumber and NSString have intValue properties. Xcode doesn't know which intValue to use, because both NSNumber and NSString fall under the AnyObject umbrella. Since Xcode is confused, you need to be more specific about what type your object is. Try something like this:
jobPackageVersion.intJobPackageId = (JobPackageVersionDictionary["intJobPackageId"]! as NSNumber).intValue
Note 1: You're probably going to get the same error with the other objects you call intValue on, but you can fix them accordingly.
Note 2: Be extremely careful about force unwrapping your objects using !. If the dictionary you're using ever returns nil your program will crash. Instead I would safely unwrap them using either an if let or guard statement depending on your use case. Something like this may work a little better:
guard let intJobPackageId = JobPackageVersionDictionary["intJobPackageId"] as? NSNumber,
let intJobPackageVersionId = JobPackageVersionDictionary["intJobPackageVersionId"] as? NSNumber,
let intStatus = JobPackageVersionDictionary["intStatus"] as? NSNumber,
let intVersion = JobPackageVersionDictionary["intVersion"] as? NSNumber
else {
print("one of the dictionary values is nil")
return
}
jobPackageVersion.intJobPackageId = intJobPackageId.intValue
jobPackageVersion.intJobPackageVersionId = intJobPackageVersionId.intValue
jobPackageVersion.intStatus = intStatus.intValue
jobPackageVersion.intVersion = intVersion.intValue
This may not be exactly what you want, but it should give you an idea on how to safely unwrap your objects so your app doesn't crash. You can play around with it and decide what's best for you.

Accessing a pointer in Swift/Obj-c to Swift Conversion with pointers

Im trying to do the following in Swift:
CFArrayRef attachmentsArray = CMSampleBufferGetSampleAttachmentsArray(sampleBuffer, 0);
if (CFArrayGetCount(attachmentsArray)) {
CFBooleanRef notSync;
CFDictionaryRef dict = CFArrayGetValueAtIndex(attachmentsArray, 0);
BOOL keyExists = CFDictionaryGetValueIfPresent(dict,
kCMSampleAttachmentKey_NotSync,
(const void **)&notSync);
I have:
if CFArrayGetCount(attachmentsArray) != 0 {
let dict = CFArrayGetValueAtIndex(attachmentsArray, 0)
However, dict is a UnsafePointer instead of a dictionary like it should be. When I printed attachmentsArray I got
Optional({ DependsOnOthers = 0; })
I tried casting it to a CFDictionaryRef but it would fail in runtime.
How do I succeed in doing the above Obj-C code in Swift?
However, dict is a UnsafePointer instead of a dictionary like it should be.
No, not "like it should be". Look at the declaration:
func CFArrayGetValueAtIndex(theArray: CFArray!, _ idx: CFIndex)
-> UnsafePointer<Void>
It returns an UnsafePointer-to-void because that is what it is supposed to do. (In Objective-C it returns a const void *.)

Sort indexPathsForSelectedRows in Swift

When you invoke tableView.indexPathsForSelectedRows(), it returns an array of AnyObject type with the indexPaths of the rows selected in the order that user has selected them.
What I want is to sort the indexPaths in order to get ascending order. Before Swift, it could be achieved with this:
NSArray *sortedIndexPaths = [[tableView indexPathsforSelectedRows]
sortedArrayUsingSelector:#selector(compare:)];
But I have tried to implement it with Swift and it does not work :S
Anyone knows how to deal with this?
Thanks in advance!
it's simple code to sort array of NSIndexPath objects stored in paths variable .
The trick is in casting to [NSIndexPath]. Now you can have your array sorted.
let paths = tableView.indexPathsForSelectedRows() as [NSIndexPath]
let sortedArray = paths.sorted {$0.row < $1.row}
OR
if you wish to have separate function for that like:
func compare (obj0: NSIndexPath, obj1: NSIndexPath) -> Bool {
return obj0.row < obj1.row
}
then
let sortedArray = paths.sorted { compare($0, $1) }
I'm on Windows 7 at the moment so I cannot test but this is what I would expect to work. It may need a type annotation.
let paths = tableView.indexPathsforSelectedRows()
let sorted = paths.sortedArrayUsingSelector("compare:")
You can overload the < and > operators and then just call sort on it.
Define this globally
func <(left: NSIndexPath, right: NSIndexPath) -> Bool {
return left.section < right.section || left.row < right.row
}
Then you can just do this for ascending
let sortedIndexPaths = tableView.indexPathsForSelectedRows?.sort(<)
Obviously because of it returns an optional you would guard against it somehow, for example
guard let sortedIndexPaths = tableView.indexPathsForSelectedRows?.sort(<) else {
return
}
Here is Sort indexPathsForSelectedRows swift 4 code.
if var selection = tableView.indexPathsForSelectedRows
{
selection = selection.sorted{ $1.compare($0) == .orderedAscending }
}
If you have any issue ping me.

Operations based on user input Swift

long question, so bear with me...
I am attempting to create a bitcoin ticker and converter written in Swift. I am using the code below (bits not related to conversion are removed - let me know if I left out anything important)
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var USD: UITextField! //Amount of USD. Originally equals 1 bitcoin, can be changed by user.
#IBOutlet weak var BTC: UILabel! //Amount of bitcoins the entered amount of USD is worth. Originally 1.
func handler(response: NSURLResponse!, data : NSData!, error : NSError!) { //To fetch Bitcoin Price. This is functional.
if ((error) != nil) {
self.USD.text = "No Internet" // in case of error
} else {
var price = NSString(data:data, encoding:NSUTF8StringEncoding)
self.USD.text = price //set USD to be equal to price of 1 Bitcoin
}
override func viewDidLoad() {
//Sets up view
self.update() //Fetches Bitcoin Price. This works.
self.convert() //Begins convert method
var timer = NSTimer.scheduledTimerWithTimeInterval(120, target: self, selector: Selector("update"), userInfo: nil, repeats: true)
}
func convert() {
var url = NSURL(string:"https://api.bitcoinaverage.com/ticker/USD/last")
var request = NSURLRequest(URL: url)
NSURLConnection.sendAsynchronousRequest(request, queue: NSOperationQueue(), completionHandler:handler)
var data = NSData(contentsOfURL:url);
while true {
if USD.text != data {
BTC.text = USD.text / NSString(data:data, encoding:NSUTF8StringEncoding)// Attempts to determine amount of bitcoin the USD amount is worth. ERROR HERE!
}
}
On the line with the comment "ERROR HERE", I get the error
/Users/[My User]/Documents/dev/Newest Stuff/CryptoCoinTicker/CryptoCoinTicker/ViewController.swift:95:32: 'String' is not convertible to 'UInt8'
In case the code doesn't tell the story, I want BTC.text to change to be equal in value to the amount entered by the user in USD.text (so if a bitcoin is worth $500, and the user entered 250.00, BTC.text would say 0.5.
What do I need to do? Apologies for a (probably) basic question, I am but a newbie. Let me know if you ned more info.
Thanks in advance!
When you get that error, it usually means that you are trying to assign a wrong type to a variable or that you are using the wrong types for function parameters.
In your case, you are trying to divide two Strings. The compiler doesn't know what to do, since the division of Strings is not defined. You can only divide Int, Float and Double and you can't even mix them!
So for that line you can substitute this:
let value = NSString(string: USD.text).doubleValue / NSString(data:data, encoding:NSUTF8StringEncoding).doubleValue
BTC.text = "\(value)"
This first "converts" the USD.text to NSString and then converts both NSStrings to Doubles, which you can then divide.
It then creates a String from that value, which can be assigned to the BTC.text property.