In Swift 4 you can convert a String myString to [Character] with Array(myString).  Then you can index that array with Int and then convert that [Character] to String.
let myString = "abc"
let thirdLetter = String(Array(myString)[2])    // "c"
let firstTwo = String(Array(myString)[0..<2])   // "ab"
If you are going to do a lot of operations on a String, it is frequently better to just convert and keep it as [Character].
Note: I have reworked this section to try to avoid any caching optimizations the compiler might do.  Each method is now measured just once and a running total is kept for each method.
Converting to Array and indexing with Int is easy to write and read, but how does it perform?  To answer this, I tested the following in a release build:
func time1(str: String, n: Int) -> (Double, String) {
    // Method 1: Index string with String.Index, convert to String
    let start = Date()
    let a = String(str[str.index(str.startIndex, offsetBy: n)])
    let interval = Date().timeIntervalSince(start)
    return (interval, a)
}
func time2(str: String, n: Int) -> (Double, String) {
    // Method 2: Convert string to array, index with Int, convert to String
    let start = Date()
    let a = String(Array(str)[n])
    let interval = Date().timeIntervalSince(start)
    return (interval, a)
}
func time3(str: String, n: Int) -> (Double, String) {
    // Method 3: Use prefix() and last(), convert to String
    let start = Date()
    let a = String(str.prefix(n + 1).last!)
    let interval = Date().timeIntervalSince(start)
    return (interval, a)
}
func time4(str: String, n: Int) -> (Double, String) {
    // Method 4: Use Leo Dabus' extensions
    // https://stackoverflow.com/q/24092884/1630618
    let start = Date()
    let a = str[n]
    let interval = Date().timeIntervalSince(start)
    return (interval, a)
}
func time5(str: String, n: Int) -> (Double, String) {
    // Method 5: Same as 2 but don't measure Array conversion time
    let arr = Array(str)
    let start = Date()
    let a = String(arr[n])
    let interval = Date().timeIntervalSince(start)
    return (interval, a)
}
func test() {
    for repetitions in [1, 10, 100, 1000] {
        var input = ""
        for _ in 0 ..< repetitions {
            input.append("abcdefghijklmnopqrstuvwxyz")
        }
        var t = [0.0, 0.0, 0.0, 0.0, 0.0]
        let funcs = [time1, time2, time3, time4, time5]
        for i in 0 ..< input.count {
            for f in funcs.indices {
                let (interval, _) = funcs[f](input, i)
                t[f] += interval
            }
        }
        print("For string length \(input.count):")
        for i in 0 ..< 5 {
            print(String(format: "Method %d time: %.8f", i + 1, t[i]))
        }
        print("")
    }
}
Results:
For string length 26:
Method 1 time: 0.00108612
Method 2 time: 0.00085294
Method 3 time: 0.00005889
Method 4 time: 0.00002104
Method 5 time: 0.00000405
For string length 260:
Method 1 time: 0.00117570
Method 2 time: 0.00670648
Method 3 time: 0.00115579
Method 4 time: 0.00110406
Method 5 time: 0.00007111
For string length 2600:
Method 1 time: 0.09964919
Method 2 time: 0.57621503
Method 3 time: 0.09244329
Method 4 time: 0.09166771
Method 5 time: 0.00087011
For string length 26000:
Method 1 time: 9.78054154
Method 2 time: 56.92994779
Method 3 time: 9.02372885
Method 4 time: 9.01480001
Method 5 time: 0.03442019
Analysis:
- The conversion to array is expensive, especially as the array size grows.
- If you can keep the converted [Character]around, the indexing operations on it are quite quick.  (see Method 5)
- Methods 1, 3, and 4 are all about the same speed, so choose based on your own personal preference.