Converting Swift 2.0 to Swift 3.0 - swift

I am currently writing a iOS App using AWS Mobile Hub and the AWS services. I'm in the middle of implementing API Gateway into my app after connecting it with an AWS Lambda function. After doing all that, AWS generated an SDK for me to implement into my project but the problem is, is that the code is in Swift 2.0. I am trying to convert it into Swift 3.0 but I have no idea what this code is supposed to do/trying to do, so I don't know how to convert it.
My question is, how do I convert this line into Swift 3.0?
var URLString: String = "https://XXXXX.execute-api.XXXX.amazonaws.com/prod"
if URLString.hasSuffix("/") {
URLString = URLString.substringToIndex(URLString.startIndex.advancedBy(URLString.lengthOfBytesUsingEncoding(NSUTF8StringEncoding) - 1))
}
The problem is the line of code in the "if" statement.
Thank you.

Swift 3 version:
var URLString: String = "https://XXXXX.execute-api.XXXX.amazonaws.com/prod"
if URLString.hasSuffix("/") {
let index = URLString.index(URLString.startIndex, offsetBy: (URLString.characters.count - 1))
URLString = URLString.substring(to: index)
}
Please use camelcase starting from small letter with naming your variables within Swift. More convenient way:
var urlString: String = "https://XXXXX.execute-api.XXXX.amazonaws.com/prod"
if urlString.hasSuffix("/") {
urlString = String(urlString.characters.dropLast())
}

Related

Parse an URL-path based rest API

I'm create a client app using a REST API. This one use a URL-path format, i.e /api/subPath/{variable}/otherSubPath
I know Apple gives a URLComponents class but seems to work very well only for URL-query-argument i.e /api/path?param=value
I would like to create a class URLBuilder for giving me the different API url dynamically. For the moment I ended up with a class who looks like this:
class URLBuilder {
fileprivate static let base = "https://theAPI.com/"
fileprivate static let objectsPath = kBase + "objects/"
static func informationOfObject(withID id: Int) {
return objectsPath + "\(id)/" + "information/"
}
// Many other functions like this
}
So I would like to know how to get something more elegant (if possible) and maybe use URL-path format with URLComponents.
Or maybe should I use regex? I've never use it but maybe it's useful here.
Have you looked into using the append... family of functions from URL?
appendPathComponent(_:)
appendPathComponent(_:isDirectory:)
appendingPathComponent(_:)
appendingPathComponent_:isDirectory:)
If I understand your requirements, you can do something like:
let baseURL = URL(string: "/api/subPath")!
let variableURL = baseURL.appendingPathComponent("variable")
let trailingURL = variableURL.appendingPathComponent("otherSubPath")
print(trailingURL.absoluteString)
Output: api/subPath/variable/otherSubPath
You could even chain the appending calls together if you need it on a single line.

How Can I Run JXA from Swift?

If I have a string variable with JXA source code, is there a way to run that from swift? It seems NSAppleScript only works with AppleScript source.
Here is an example showing how to use OSAKit from Swift to run a JavaScript for Automation script stored in a string:
import OSAKit
let scriptString = "Math.PI";
let script = OSAScript.init(source: scriptString, language: OSALanguage.init(forName: "JavaScript"));
var compileError : NSDictionary?
script.compileAndReturnError(&compileError)
if let compileError = compileError {
print(compileError);
return;
}
var scriptError : NSDictionary?
let result = script.executeAndReturnError(&scriptError)
if let scriptError = scriptError {
print(scriptError);
}
else if let result = result?.stringValue {
print(result)
}
This Swift code was adapted from the Hammerspoon source code (Objective-C).
Why? JXA is a dog in every respect. If you just want to run JS code, the JavaScriptCore Obj-C API is far cleaner and easier. If you want to control "AppleScriptable" applications then use AppleScript—it's the only officially supported† option that works right.
(† There is SwiftAutomation, but Apple haven't bitten and I'm not inclined to support it myself given Apple's chronic mismanagement of Mac Automation. We'll see what happens with WWDC17.)

What is the Swift 3 equivalent of NSURL.URLByAppendingPathComponent()?

I'm following a basic tutorial on building a simple iOS app in Swift.
It is written in Swift 2.x, and I work with XCode 8 Beta and Swift 3.
The tutorial suggests using NSFileManager to find a data directory. Class names have changed, so the auto-fixed Swift 3 looks like this:
static let DocumentsDirectory = FileManager().urlsForDirectory(.documentDirectory, inDomains:.userDomainMask).first!
static let ArchiveURL = DocumentsDirectory.URLByAppendingPathComponent("meals")
However, Xcode now complains that
Value of type 'URL' has no member 'URLByAddingPathComponent'
I am unable to find out what the method is called now.
The NSURL Class Reference doesn't contain any hints as to how to address it from Swift 3
What is the new method name?
Where do I have to go to find a complete class reference for Swift 3 (or, the Swift 3 interface to the library the URL class is defined in - I still don't completely understand the nomenclature) so I can research these myself in the future?
As of Xcode 8 beta 4, it is named appendingPathComponent(_:), and does not throw.
static let archiveURL = documentsDirectory.appendingPathComponent("meals")
Also as Leo Dabus points out in the comments, your documentsDirectory property will need changing to use urls(for:in:) in beta 4:
static let documentsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
(Note that I've made your property names lowerCamelCase, as per the Swift API design guidelines. I would also recommend using FileManager.default, rather than creating a new instance.)
You can take a look at Apple's latest API reference guide to see the API naming changes that have taken place in Swift 3.
It has now changed to appendingPathComponent(_:) and it throws, so you need to wrap it in do - catch block
do {
let archiveURL = try documentsDirectory?.appendingPathComponent("meals")
} catch {
print(error)
}
Update
As per Xcode 8 beta 4, the appendingpathcomponent(_:) do not throw error.
For relevant info see answer by #Hamish
func appendingPathComponent(String)
=> Returns a new URL made by appending a path component to the original URL.
static let archiveURL = documentsDirectory?.appendingPathComponent("meals")
If it is directory:
func appendingPathComponent(String, isDirectory: Bool)
=> Returns a new URL made by appending a path component to the original URL, along with a trailing slash if the component is designated a directory.
static let archiveURL = documentsDirectory?.appendingPathComponent("meals", isDirectory: true)

Use NSRunningApplications? [duplicate]

This question already has answers here:
Filtering user-launched applications (Mac OS X)
(2 answers)
Closed last month.
I am trying to have my OS X Application detect if a certain program is running but NSRunningApplications isn't working for me. This is my code:
import AppKit
class func sharedWorkspace() -> NSWorkspace
{
var runningApplications: [NSRunningApplications] {get}
}
The error I'm getting is
Expected '{' to start getter definition.
as well as
Missing return in a function expected to return 'NSWorkspace.
Any ideas?
You've got to use NSWorkspace.sharedWorkspace().runningApplications itself:
for app in NSWorkspace.sharedWorkspace().runningApplications {
if let name = app.localizedName {
print(name)
}
}
You can get the running applications names in an array with a simple map (or flatMap here to manage Optionals):
let names = NSWorkspace.sharedWorkspace().runningApplications.flatMap { $0.localizedName }
print(names)
In Swift 5+ the syntax changed to:
NSWorkspace.shared.runningApplications

Using IBM Swift Sandbox and rangeOfCharacterFromSet

I am trying swift on IBM's new Swift online Sandbox.
The following script is not running on that sandbox: http://swiftlang.ng.bluemix.net/
import Foundation
func palindromTest(s: String) -> Bool{
let lower = s.lowercaseString
let letters = NSCharacterSet.letterCharacterSet()
let onlyLetters = lower.characters.filter({String($0).rangeOfCharacterFromSet(letters) != nil})
let reverseLetters = Array(onlyLetters).reverse()
return String(onlyLetters) == String(reverseLetters)
}
palindromTest("abc")
The sandbox prints the following error message:
/swift-execution/code-tmp.swift:7:48: error: value of type 'String' has no member 'rangeOfCharacterFromSet'
let onlyLetters = lower.characters.filter({String($0).rangeOfCharacterFromSet(letters) != nil})
Did I forget to import something? Hope you can help me.
Thanks.
rangeOfCharacterFromSet is one of the many String methods
which are actually handled by NSString.
From this commit
to NSString.swift, it seems that support for rangeOfCharacterFromSet
was added only recently to the (non-Apple) Foundation library,
so you cannot use it until the IBM Swift Sandbox is updated to use
a new Swift version.
FWIW, this works now in the Sandbox swiftlang.ng.bluemix.net/#/repl/aae5d1caf4e0a6232ff428c3a0160e6e98cba6ed913ce9176f2baee46d30cb1c
Lots of things have changed since these answers were given. I've updated Pat's Sandbox answer for Swift 3.1.1. Below is the code and a summary of the API changes.
Several methods in the standard library and Foundation have since been renamed:
Array: .reverse() → .reversed()
String: .rangeOfCharacterFromSet() → .rangeOfCharacter(from:)
(NS)CharacterSet: .lettersCharacterSet() → .letters
I also made a slight change, perhaps just from personal preference. Rather than use String.rangeOfCharacter(from:) I chose to use CharacterSet.contains(), which required I use String.unicodeScalars instead of .characters. Not sure about the performance tradeoffs in general, but I liked how cleaned things up.
import Foundation
func palindromTest(_ word: String) -> Bool{
let letters = CharacterSet.letters
let onlyLetters = word.lowercased().unicodeScalars.filter {
letters.contains($0)
}.map { Character($0) }
let reverseLetters = onlyLetters.reversed()
print("\(String(onlyLetters)) == \(String(reverseLetters))")
return String(onlyLetters) == String(reverseLetters)
}
print(palindromTest("abc"))
// false
print(palindromTest("dud"))
// true