ScriptingBridge code errors in Xcode 8.0 and swift 3.0 - swift3

This is the code I used in Xcode 7.3.1 and that worked fine:
var selectedFiles = NSMutableArray(capacity:1)
let finder: AnyObject! = SBApplication(bundleIdentifier:"com.apple.finder")
let finderObject = finder.selection as! SBObject
let selection: AnyObject! = finderObject.get()
let items = selection.arrayByApplyingSelector(Selector("URL"))
let filteredfiles = (items as NSArray).pathsMatchingExtensions(["ai","pdf","ap","paf","pafsc"])
for item in filteredfiles {
let url = NSURL(string:item ,relativeToURL:nil)
selectedFiles.addObject(url!)
}
This is the code corrected for Xcode 8.0 and that does not work:
the error is generated for the last line
error = Cannot call value of non-function type '[Any]!'
var selectedFiles = NSMutableArray(capacity:1)
let finder: AnyObject! = SBApplication(bundleIdentifier:"com.apple.finder")
let finderObject = finder.selection as! SBObject
if let selection = finderObject.get() as AnyObject?{
let items = selection.array(#selector(getter: NSTextCheckingResult.url))
let filteredfiles = (items as NSArray).pathsMatchingExtensions(["ai","pdf","ap","paf","pafsc"])
for item in filteredfiles {
let url = NSURL(string:item ,relativeToURL:nil)
selectedFiles.addObject(url!)
}
}
I have tried many solutions, but unfortunately cannot find a clue.
I guess this is because Swift 3.0x APIs have changed drastically....
Any help is welcome!

This is a slightly different approach using a couple of native Swift functions for Swift 3
var selectedFiles = [URL]()
let finder : AnyObject = SBApplication(bundleIdentifier:"com.apple.finder")!
let finderObject = finder.selection as! SBObject
if let selection = finderObject.get() as? [SBObject] {
selection.forEach { item in
let url = URL(string: item.value(forKey:"URL") as! String)!
selectedFiles.append(url)
}
let goodExtensions = ["ai","pdf","ap","paf","pafsc"]
let filteredURLs = selectedFiles.filter({goodExtensions.contains($0.pathExtension)})
print(filteredURLs)
}
PS: I highly recommend to use AppleScriptObjC. It's so much easier to use.
PPS: valueForKey is intentionally used because KVC is really needed to get the property value.

Related

How to play video with cookies content in iOS using AVPlayer in Swift?

I have used the below implementation to play a video with cookies content from the server, but it shows play icon with cross line. I have refer the link and do following implementation in swift. but I didn't get any output :(
func showVideo(url: String) {
let videoURL = NSURL(string: url)
var cookiesArray = [HTTPCookie]()
guard let cookieArray = UserDefaults.standard.array(forKey:
Constants.Object.kCookie) as? [[HTTPCookiePropertyKey: Any]] else {
return }
for cookieProperties in cookieArray {
if let cookie = HTTPCookie(properties: cookieProperties) {
cookiesArray.append(cookie)
}
}
let cookieArrayOptions = [AVURLAssetHTTPCookiesKey: cookiesArray]
let assets = AVURLAsset(url: videoURL! as URL, options: cookieArrayOptions)
let item = AVPlayerItem(asset: assets)
videoPlayer = AVPlayer(playerItem: item)
self.playerController.player = self.videoPlayer
self.playerController.view.frame = self.view.frame
self.present(self.playerController, animated: true, completion: nil)
self.playerController.player?.play()
}
Please help me on that, what is wrong in that implementation.
Thanks in advance! :)
After going through so many ways finally I have got the solution which worked for me :
func showVideo(url: String) {
let videoURL = NSURL(string: url)
let cookiesArray = HTTPCookieStorage.shared.cookies! //Stored Cookies of your request
let values = HTTPCookie.requestHeaderFields(with: cookiesArray)// Returns a dictionary of header fields corresponding to a provided array of cookies.ex.["Cookie":"your cookies values"]
let cookieArrayOptions = ["AVURLAssetHTTPHeaderFieldsKey": values]
let assets = AVURLAsset(url: videoURL! as URL, options: cookieArrayOptions)
let item = AVPlayerItem(asset: assets)
videoPlayer = AVPlayer(playerItem: item)
self.playerController.player = self.videoPlayer
self.playerController.view.frame = self.view.frame
self.present(self.playerController, animated: true, completion: nil)
self.playerController.player?.play()
}

How to get window id from the title by swift3

How can I get a CGWindowID from the title of it?
I thought I can get list of titles by this code
let options = CGWindowListOption(arrayLiteral: CGWindowListOption.excludeDesktopElements, CGWindowListOption.optionOnScreenOnly)
let windowListInfo = CGWindowListCopyWindowInfo(options, CGWindowID(0))
let infoList = windowListInfo as NSArray? as? [[String: AnyObject]]
https://stackoverflow.com/a/31367468/1536527
But it seems there is no info for title of the windows.
How can I get CGWindowID or any info to specify a window by title?
Actually the code snippet you posted seems to work for me. All I did was to iterate over the dictionary and find the window info for a given window title.
Here is the code:
func getWindowInfo(pname: String) -> Dictionary<String, AnyObject> {
var answer = Dictionary<String, AnyObject>()
let options = CGWindowListOption(arrayLiteral: CGWindowListOption.optionOnScreenOnly)
let windowListInfo = CGWindowListCopyWindowInfo(options, CGWindowID(0))
let infoList = windowListInfo as NSArray? as? [[String: AnyObject]]
infoList?.forEach{eachDict in
eachDict.keys.forEach{ eachKey in
if (eachKey == "kCGWindowName" && eachDict[eachKey] != nil ){
let name = eachDict[eachKey] as? String ?? ""
print (name)
if ( name == pname){
print("******** Found **********")
answer = eachDict as! Dictionary<String, AnyObject>
}
}
print(eachKey , "-->" , eachDict[eachKey])
}
}
return answer
}
With the above function, I am able to get a window's details, including name for example.
I hope it works for you too.

Swift 3 Change color of selected text in UITextView

I have just changed my code to Swift 3 from swift 2.3. The following code is working fine with swift 2.3 but there is no effect with swift 3.
I want to develop a customise text editor. And let user to select text and change its color. For that i am using this code.
let selectedRange = textView.selectedRange
let currentAttr = textView.textStorage.attributes(at: selectedRange.location, effectiveRange: nil)
var attrName = NSForegroundColorAttributeName
if !isForeGround{
attrName = NSBackgroundColorAttributeName
}
if currentAttr[attrName] == nil || currentAttr[attrName] as! UIColor != selectedUIColor{
let dict = [attrName:selectedUIColor]
let currentFont = currentAttr[NSFontAttributeName]
let fontDescriptor = (currentFont! as AnyObject).fontDescriptor
let updatedFont = UIFont(descriptor: fontDescriptor!, size: 0.0)
let dict2 = [NSFontAttributeName: updatedFont]
textView.textStorage.beginEditing()
if currentAttr.count>0{
textView.textStorage.addAttributes(dict, range: selectedRange)
}else{
textView.textStorage.setAttributes(dict, range: selectedRange)
}
textView.textStorage.addAttributes(dict2, range: selectedRange)
textView.textStorage.endEditing()
}
Runs successfully but there is no effect on text color.
This worked for me.
First you need to catch your selected text, with:
let selectedText = textView.selectedRange
Then, you create the attribute:
let myAttribute = [ NSForegroundColorAttributeName: selectedUIColor]
And lastly:
textView.textStorage.addAttributes(myAttribute, range: selectedText)
This must be in an Action called by any sender
Hope it works also for you!
Regards
Selected text can be changed with
self.textView.tintColor = .red

lazy var NSFetchedResultsController producing error in Swift 3.0

I just migrated my project to Swift 3 and am stuck on an error for my lazy instantiated NSFetchResultController. I use this method here :
https://www.andrewcbancroft.com/2015/03/05/displaying-data-with-nsfetchedresultscontroller-and-swift/
My current code
lazy var fetchedResultsController: NSFetchedResultsController = {
let primarySortDescriptor = NSSortDescriptor(key: "company", ascending: true)
let sortDescriptors = [primarySortDescriptor]
self.fetchRequest.sortDescriptors = sortDescriptors
let frc = NSFetchedResultsController(
fetchRequest: self.fetchRequest,
managedObjectContext: self.managedObjectContext!,
sectionNameKeyPath: nil,
cacheName: nil)
frc.delegate = self
return frc
}()
It produces 2 errors as shown below
Is this method no longer possible under Swift 3? I tried adding () -> <<error type>> in as suggested by Xcode but failed to produce the correct results.
The suggested () -> <<error type>> is misleading.
In Swift 3 NSFetchedResultsController has become a generic type.
You have to initialize it:
lazy var fetchedResultsController: NSFetchedResultsController<NSFetchRequestResult> = {
...
}()
as well as NSFetchRequest
let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "MyEntity")
If you are using a subclass of NSManagedObject – which is recommended – you can use the subclass type for being more specific
lazy var fetchedResultsController: NSFetchedResultsController<MyEntity> = {
....
let fetchRequest = NSFetchRequest<MyEntity>(entityName: "MyEntity")
The huge benefit is you get rid of all type casts using fetch, insert etc.

Argument type NSURL does not conform

I am working from an old tutorial swift2, Alamofire 3, but I am using swift 3, Alamofire 4.
I have changed most things successfully, but I am running into a problem.
with this code area.
let url = NSURL(string: _pokemonUrl)!
Alamofire.request(url).responseJSON { response in
let result = response.result
I am getting an error that says:
Argument type NSURL does not conform to expected type
URLRequestConvertible.
it does give me the option of adding in as! URLRequestConvertible after the (url) but it crashes again after compile and when i press the button to get the info. it gives an error of:
Could not cast value of type 'NSURL' (0x117e99338) to
'Alamofire.URLRequestConvertible' (0x1189ab120).
if I change NSURL to Url then it moves forward in the code but when it gets to the print statement it crashes and gives the error:
fatal error: unexpectedly found nil while unwrapping an Optional value
here is that code below.
let url = URL(string: _pokemonUrl)!
Alamofire.request(url).responseJSON { response in
let result = response.result
if let dict = result.value as? Dictionary<String, AnyObject> {
if let weight = dict["weight"] as? String {
self._weight = weight
}
if let height = dict["height"] as? String {
self._height = height
}
if let baseAttack = dict["attack"] as? Int {
self._baseAttack = "\(baseAttack)"
}
if let defense = dict["defense"] as? Int {
self._defense = "\(defense)"
}
print(self._weight)
print(self._height)
print(self._baseAttack)
print(self._defense)
I have tried to change all to Int but i get the same error.
Can anyone shed any light on this for me.
if it helps I put a break point in after print("Here") in the next code and it gives me the following error.
let url = URL(string: _pokemonUrl)!
Alamofire.request(url).responseJSON { response in
let result = response.result
print(result.value.debugDescription)
print("Here")
error comes up:
Optional({
"error_message" = "Sorry, this request could not be processed. Please try again later.";
})
Here
Thanks in advance,
Tony
You almost did it guys, just a cast to URL was missing.
let nsurl = NSURL(string: _pokemonUrl)!
let request = URLRequest(url: nsurl as URL)
Alamofire.request(request).responseJSON { response in
let result = response.result
...
}
I tried folowing & it's helped
func downloadPokemonDetails(completed: DownloadComplete) {
let url = URL(string: _pokemonUrl)!
Alamofire.request(URLRequest(url: url)).responseJSON { response in
if let result = response.result.value as? [String: Any]{
print(result.debugDescription)
}
}
}