Why does swift gives an error when I set the offsetBy value equal to endIndex value in the index(_ , offsetBy , limitedBy) function?
The problem is that the limit given to index(_:offsetBy:limitedBy:)
is an inclusive bound for the result. Therefore with
let someString = "hello"
the index returned by
someString.index(someString.startIndex, offsetBy: 5, limitedBy: someString.endIndex)
will be someString.endIndex
, which is a past the end index, and therefore not a valid index to subscript the string with.
A simple solution therefore would be to just add a condition to your if
statement to check that the index you get back isn't the endIndex
:
let someString = "hello"
let offset = 5
if let someIndex = someString.index(someString.startIndex,
offsetBy: offset,
limitedBy: someString.endIndex
), someIndex != someString.endIndex {
print(someString[someIndex])
}
Or a nicer option would be to use the CharacterView
's indices
property in order to get a collection of valid indices to subscript with (excluding endIndex
), and use dropFirst(_:)
and first
in order to get the index at the given offset:
if let index = someString.characters.indices.dropFirst(offset).first {
print(someString[index])
}
This takes advantage of the fact that dropFirst(_:)
takes an upper bound of elements to drop, returning an empty subsequence if it's larger than the collection's count, as well as the fact that first
returns nil
for an empty collection.
How does String.Index work in Swift
All of the following examples use
var str = "Hello, playground"
startIndex
and endIndex
startIndex
is the index of the first characterendIndex
is the index after the last character.
Example
// character
str[str.startIndex] // H
str[str.endIndex] // error: after last character
// range
let range = str.startIndex..<str.endIndex
str[range] // "Hello, playground"
With Swift 4's one-sided ranges, the range can be simplified to one of the following forms.
let range = str.startIndex...
let range = ..<str.endIndex
I will use the full form in the follow examples for the sake of clarity, but for the sake of readability, you will probably want to use the one-sided ranges in your code.
after
As in: index(after: String.Index)
after
refers to the index of the character directly after the given index.
Examples
// character
let index = str.index(after: str.startIndex)
str[index] // "e"
// range
let range = str.index(after: str.startIndex)..<str.endIndex
str[range] // "ello, playground"
before
As in: index(before: String.Index)
before
refers to the index of the character directly before the given index.
Examples
// character
let index = str.index(before: str.endIndex)
str[index] // d
// range
let range = str.startIndex..<str.index(before: str.endIndex)
str[range] // Hello, playgroun
offsetBy
As in: index(String.Index, offsetBy: String.IndexDistance)
- The
offsetBy
value can be positive or negative and starts from the given index. Although it is of the typeString.IndexDistance
, you can give it anInt
.
Examples
// character
let index = str.index(str.startIndex, offsetBy: 7)
str[index] // p
// range
let start = str.index(str.startIndex, offsetBy: 7)
let end = str.index(str.endIndex, offsetBy: -6)
let range = start..<end
str[range] // play
limitedBy
As in: index(String.Index, offsetBy: String.IndexDistance, limitedBy: String.Index)
- The
limitedBy
is useful for making sure that the offset does not cause the index to go out of bounds. It is a bounding index. Since it is possible for the offset to exceed the limit, this method returns an Optional. It returnsnil
if the index is out of bounds.
Example
// character
if let index = str.index(str.startIndex, offsetBy: 7, limitedBy: str.endIndex) {
str[index] // p
}
If the offset had been 77
instead of 7
, then the if
statement would have been skipped.
Why is String.Index needed?
It would be much easier to use an Int
index for Strings. The reason that you have to create a new String.Index
for every String is that Characters in Swift are not all the same length under the hood. A single Swift Character might be composed of one, two, or even more Unicode code points. Thus each unique String must calculate the indexes of its Characters.
It is possible to hide this complexity behind an Int index extension, but I am reluctant to do so. It is good to be reminded of what is actually happening.
Xcode Playground bug? fatal error: Can't form a Character from an empty String
The problem is from the expression s[idx]
when idx
is too large. The error goes away when you update the calculation of idx
to:
if let idx = s.index(s.startIndex, offsetBy: i + 1, limitedBy: s.index(s.endIndex, offsetBy: -1)) {
or, as kindly suggested by Leo,
if let idx = s.index(s.startIndex, offsetBy: i + 1, limitedBy: s.index(before: s.endIndex)) {
Runtime Error when Trying Bottom Up Approach to Implement Fibonacci function in Swift?
You have no recursion in your code.
Note that Fib(35) is too small for integer overflow, but Fib(100) definitely is too large both for 32-bit and for 64-bit integers, so your compiler catches integer overflow error.
You may set limit n=41 for 32-bit signed ints and n=92 for 64-bit signed ints.
Higher values require using of long/arbitrary precision integer arithmetics.
value(forKey:) for NSObject not working in Swift 4
Key-value coding requires Objective-C. In Swift 4 you have to mark members accessible from Obj-C explicitly:
@objcMembers
class Person: NSObject {
or
class Person: NSObject {
@objc var name = ""
var age = 0
}
See Swift Evolution 160
How to use do-catch functions in Swift
You can just add throws to your method signature and throw a custom error. I would also make the method generic and extend StringProtocol
instead of String
to support Substring
as well. Note that constraining to RangeReplaceableCollection
is required to be able to use mutating func insert<S>(contentsOf newElements: S, at i: Index) where S: Collection, Element == S.Element
:
extension String {
enum Error: Swift.Error {
case invalidIndexDistance
}
}
extension StringProtocol where Self: RangeReplaceableCollection {
mutating func insert<S: StringProtocol>(contentsOf string: S, at distance: Int) throws {
guard let index = self.index(startIndex, offsetBy: distance, limitedBy: endIndex) else {
throw String.Error.invalidIndexDistance
}
insert(contentsOf: string, at: index)
}
}
var substring = "abcde".dropFirst()
do {
try substring.insert(contentsOf: "fgh", at: 2)
substring // "bcfghde"
} catch {
print(error)
}
NSLinguisticTaggerOptions in swift
For the options
parameter, try Int(opts.toRaw())
.
(The "3" that you tried worked because it is the raw version.)
My code in Swift vs. Java. Swift gives an error but Java doesn't. Are there any differences?
No, apple didn't get rid of the for in
loops.
Your problem is, that line:
for l in 2...i-1 {
Because if i-1
is less than 2, this error occurs. So you need to make a check, if i-1 is equal or greater than 2. check this code to prove the error:
for l in 2...2 { //No error
for l in 2...1 { //error
So I would make something like that, if you want to keep your code:
if(i-1 >= 2){
for a in 2...i-1 {
if ((i%a) == 0) {
isPrimeFactor = false
}//end if
}//end for
}
Also you have an error here:
if (isPrimeFactor == true) {
i
}//end if
You need to either wrap the i into an println(i)
or remove it.
Related Topics
Convert Single File to Swift 3 in Xcode 8
Swift Error "Domain=Nscocoaerrordomain Code=3840 "Invalid Value Around Character 1."
Uibutton Action Is Not Triggered After Constraint Layouts Changed
Why Is Inceptionv3 Machine Learning Model Not Recognized on My Project
Xcodebuild Commands Failed to Generate Ipa
Override UIgesturerecognizer Touchesbegan
Conversion Between Cgfloat and Nsnumber Without Unnecessary Promotion to Double
Bad_Access During Recursive Calls in Swift
How to Retrieve The Name of Participants in Msconversation
How to Cast from Cftyperef to Axuielement in Swift
Easiest Way to Truncate Float to 2 Decimal Places
Nil Cannot Be Assigned to Type Avcapturedeviceinput
Difference Between Firinstanceid.Instanceid().Token() and Messaging.Messaging().Fcmtoken
How to Test If an Instance Is a Specific Class or Type in Swift
Swift iOS14 Datepicker Text Alignment
Preferredstatusbarupdateanimation Being Ignored
"This Class Is Not Key Value Coding-Compliant" Using Coreimage