Swift 4: 'subscript' is unavailable error - swift

I'm using the MapBox navigation framework that hasn't quite been updated to Swift 4. I have one 'subscript' error that I can't quite get around. Here's the code. I'd really appreciate any help. Thank you.
private func extractNextChunk(_ encodedString: inout String.UnicodeScalarView) throws -> String {
var currentIndex = encodedString.startIndex
while currentIndex != encodedString.endIndex {
let currentCharacterValue = Int32(encodedString[currentIndex].value)
if isSeparator(currentCharacterValue) {
let extractedScalars = encodedString[encodedString.startIndex...currentIndex]
encodedString = encodedString[encodedString.index(after: currentIndex)..<encodedString.endIndex]
return String(extractedScalars)
}
currentIndex = encodedString.index(after: currentIndex)
}
throw PolylineError.chunkExtractingError
}

The error message is misleading. The real problem is that subscripting
a String.UnicodeScalarView with a range returns a String.UnicodeScalarView.SubSequence, so you cannot assign that back to
encodedString.
One solution would be to create a String.UnicodeScalarView
from the subsequence:
encodedString = String.UnicodeScalarView(encodedString[encodedString.index(after: currentIndex)...])
Alternatively (and perhaps simpler) go the other way around and
remove the initial part of encodedString instead:
encodedString.removeSubrange(...currentIndex)
In either case, you can take use "one-sided ranges", compare
SE-0172

Related

No exact matches in call to initializer when initializing Data in AppStorage

I'm learning how to store custom types in AppStorage, and came across an issue. In this simplified example, I'm trying to save an empty Int array to AppStorage once the view is created.
The following code gives me the error, No exact matches in call to initializer . I know that this error usually means there are mismatching types somewhere, but I'm not sure what the types should be, or how to fix it.
struct test: View {
init() {
let emptyList = [Int]()
guard let encodedList = try? JSONEncoder().encode(emptyList) else { return }
self.storedList = encodedList
}
#AppStorage("stored_list") var storedList: Data //NO EXACT MATCHES TO CALL IN INITIALIZER
//"body" implementation not shown
}
Why is this error occurring, and how can I fix it?
It should be either with default value or optional, so correct variants are
#AppStorage("stored_list") var storedList: Data = Data()
or
#AppStorage("stored_list") var storedList: Data?

'withUnsafeMutableBytes' is deprecated: use `withUnsafeMutableBytes<R>

I am very green with Xcode (apologize in advance). Trying to bring some old code to life. Getting the following with trying to move to Swift 5.
withUnsafeMutableBytes' is deprecated: use withUnsafeMutableBytes<R>(_: (UnsafeMutableRawBufferPointer) throws -> R) rethrows -> R instead
Goal: All I need to do is modify the code appropriately and be done.
I have looked at other Stack Overflow messages, searched various articles, experimented with different things, but can't quickly determine what needs to change. I am sure the solution is super simple for someone that knows more.
var responseData = Data(count: Int(responseDataLength))
_ = responseData.withUnsafeMutableBytes
{
mfError = MFMediaIDResponse_GetAsString(mfMediaIdResponsePtr.pointee, MFString($0), responseDataLength)
}
Here is my example, when refreshing old code of withUnsafeMutableBytes
hope it helps
The old one:
_ = data.withUnsafeMutableBytes { (bytes: UnsafeMutablePointer<UInt8>) in
memcpy((ioData.pointee.mBuffers.mData?.assumingMemoryBound(to: UInt8.self))!, bytes, dataCount)
}
The new one:
_ = data.withUnsafeMutableBytes { (rawMutableBufferPointer) in
let bufferPointer = rawMutableBufferPointer.bindMemory(to: UInt8.self)
if let address = bufferPointer.baseAddress{
memcpy((ioData.pointee.mBuffers.mData?.assumingMemoryBound(to: UInt8.self))!, address, dataCount)
}
}
Explains:
use UnsafeMutablePointer<ContentType>, you get an unsafeMutablePointer in its closure.
To access to its memory, so need to typed it with bindMemory,
more details on Apple Pointer Doc

How do I rewrote this peace of code in swift 2

I am trying to make my first app and I am stuck. I don't know how to rewrite this piece of code from an earlier version of Swift in Swift 2.
func rowCheck(value value:Int) -> (location :String,pattern :String)?{
let acceptableFinds = ["101","110","011"]
var findFunc = [checkGornjiR,checkSrednjiR,checkDonjiR,checkLevuK,checkSrednjuK,checkDesnuK,checkLevuD,checkDesnuD]
for algorithm in findFunc{
let algorithmResults = algorithm(value:value)
if find(acceptableFinds,algorithmResults.pattern) { // Error on this line
return algorithmResults
}
}
return nil
In "if" line I am getting error:
"Optional type 'C.index?' cannot be used as a boolean; test for '!=nil' instead
A bit of help would be nice! Thanks!
you van use contains which return Bool value like this:
if acceptableFinds.contains(algorithmResults.pattern) {

Accessing a Dictionary using user input returning double value

I'd like the user to input a String to access a key in the dictionary which then returns its coupled value. I'm sure this isn't the only thing wrong with my code but trying to see if I have the right idea and hoping for some additional direction:
Main two issues are writing the correct syntax to connect the user input getInput() (String) inside the function callfunc planetAndTime()The function is passing my dictionary as a parameter.
My other issue is returning my function's double value. ->Double`
func getInput() -> String{
let kb: NSFileHandle = NSFileHandle.fileHandleWithStandardInput()
let inputData: NSData = kb.availableData
let strData = NSString(data: inputData, encoding:NSUTF8StringEncoding) as! String
return strData
}
/////////
let nameOfPlanetsAndTime:[String:Double] = ["Mercury":0.00000816,
"Venus":0.00044, "Mars":0.0000239, "Jupiter":0.00062, "Saturn":0.000204,
"Uranus":0.000289, "Neptune":0.000459, "Pluto":0.000794,
"Center of the Milky Way":25000.000000, "Earth's Cousin":1400.000000]
print("Choose planet")
func planetAndTime(nameOfPlanetsAndTime: [String:Double], userLocation:String) ->Double{
let userLocation = getInput()
if (nameOfPlanetsAndTime[userLocation] < 0){
print("Not a Valid Location, Please Try Again")}
else{
nameOfPlanetsAndTime[userLocation]!
print(nameOfPlanetsAndTime)
}
}
There are a few issues with your code that are due to a misunderstanding of how the Swift language works so I would recommend going through the official Swift documentation for some good examples of the Swift features. To give you a little head start however I will choose a section of your code. For example, instead of writing"
if (nameOfPlanetsAndTime[userLocation] < 0){
print("Not a Valid Location, Please Try Again")}
you can write
guard let planet = nameofPlanetsAndTime[userLocation] {
print("Not a Valid Location, Please Try Again")
return nil
}
return planet
and change the return type of your function to an optional Double. So the method signature would look like
func planetAndTime(nameOfPlanetsAndTime: [String:Double], userLocation:String) ->Double?
Understanding optionals is super important in the Swift "world" and I highly recommend taking a good look at how to use them. I hope this little example is helpful.
https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/TheBasics.html#//apple_ref/doc/uid/TP40014097-CH5-ID309

How can I test if an integerForKey is equal to nil? Using NSUserDefaults

So far, I have a function that tries to see if someone already has a code, and if they do not already have one, then it would generate one for them.
func checkID() -> Int{
if (NSUserDefaults.standardUserDefaults().integerForKey("Code") != nil) {
}
else{
var code = Int(arc4random_uniform(1000000000))
NSUserDefaults.standardUserDefaults().setInteger(code, forKey: "Code")
}
return NSUserDefaults.standardUserDefaults().integerForKey("Code")
}
I get an error message when I try to to say NSUserDefaults.standardUserDefaults().integerForKey("Code") != nil
The error message I get is "Type 'Int' does not conform to protocol 'NilLiteralConvertible'"
What can I do to try to get around this? What am I doing wrong?
The integerForKey always returns a value. If nothing's there, just 0.
So you should check like that:
if let currentValue = NSUserDefaults.standardUserDefaults().objectForKey("Code"){
//Exists
}else{
//Doesn't exist
}
The short answer is "you can't." There's no way to tell if a zero result for integerForKey represents a stored zero value, or no value.
Christian's answer of using objectForKey (which returns an optional) and optional binding is the correct answer.
Edit:
It would be quite easy to add an extension to UserDefaults with a function that returned an Optional Int:
extension UserDefaults {
func int(forKey key: String) -> Int? {
return object(forKey: key) as? Int
}
}
(I suspect that if Apple were designing the Foundations framework today, using Swift, integer(forKey:) would return an Optional(Int).)
You should be able to remove the '!= nil'. For instance,
if (NSUserDefaults.standardUserDefaults().integerForKey("Code")) {
}
else{
var code = Int(arc4random_uniform(1000000000))
NSUserDefaults.standardUserDefaults().setInteger(code, forKey: "Code")
}
return NSUserDefaults.standardUserDefaults().integerForKey("Code")
Simply retrieving the value of the key should return false if the integer is not found.