“Cannot assign to value: 'i' is a 'let

2019-09-19 14:07发布

问题:

I am updating my project to Swift 3. Most all has gone well, but I cannot figure the below out. I believe I have found how to correct the first of the two errors, but cannot figure out the second one "i = i + 1" as I am getting the error "Cannot assign to value: 'i' is a 'let' constant"

I hired someone to do the coordinates on my app, so this is why I am not so accustomed to these types of errors.

I have created 200 polygon regions and the below this is meant to take the users current location and determine with region they are located in and use the data from that region.

I saw this question, but cannot see how this answers my question. Cannot assign to value: 'i' is a 'let' constant in swift

func format_subRegion_Array_Elements_To_sub_Elements(_ one_element_in_subRegionArray : String) -> [CLLocationCoordinate2D]

{

var boundary: [CLLocationCoordinate2D]

var Boundary_points_in_string_format : [String]
    var Array_of_one_element_in_subRegionArray : [String] = one_element_in_subRegionArray.components(separatedBy: ",")


Boundary_points_in_string_format = []

//  ORIGINAL statement
//  for var i = 0 ; i <= Array_of_one_element_in_subRegionArray.count-1 ; i += 1

//  UPDATED statement
    for (i, sender) in Array_of_one_element_in_subRegionArray.enumerated()

    {
        Boundary_points_in_string_format += [String(Array_of_one_element_in_subRegionArray[i]+","+Array_of_one_element_in_subRegionArray[i+1])]


//  Still get "Cannot assign to value: 'i' is a 'let' constant" error here
        i = i+1

    }

  let  boundaryPointsCount = Boundary_points_in_string_format.count

boundary = []

for i in 0...boundaryPointsCount-1
{

    let newArrayElement  = Boundary_points_in_string_format[i].components(separatedBy: ",")

    let myDouble1 = Double(newArrayElement[0])
    let myDouble2 = Double(newArrayElement[1])
    boundary += [CLLocationCoordinate2DMake(CLLocationDegrees(myDouble1!), CLLocationDegrees(myDouble2!))]

}

return boundary
}

Thanks

UPDATED with more data from the class. @Alexander Momchliov, I have updated the "bad" area with your code, but get a single error

let polygon = MKPolygon(coordinates: &boundary, count: boundary.count)

The error is "Cannot convert value type '(String)' -> [CLLocaitonCoordinate2D]' to expected argument type "CLLocationCoordinate2D'" and points to the &boundry

func scanAllGPSData(_ currentLatitude : Double , currentLongitude : Double)->Bool
{
    for i in 0 ... subRegionArray.count-1

    {
        let singleElementInSubRegionArray = subRegionArray[i].coordinates as String

        var boundary = formatSubRegionArray(singleElementInSubRegionArray: )

        let polygon = MKPolygon(coordinates: &boundary, count: boundary.count)

        let polygonRenderer = MKPolygonRenderer(polygon: polygon)

        let currentLocationCoordinate : CLLocationCoordinate2D = CLLocationCoordinate2DMake( currentLatitude,currentLongitude)

        let currentMapPoint: MKMapPoint = MKMapPointForCoordinate(currentLocationCoordinate)
        let polygonViewPoint: CGPoint = polygonRenderer.point(for: currentMapPoint)

//                if CGPathContainsPoint(polygonRenderer.path, nil, polygonViewPoint, true)

            if polygonRenderer.path.contains(polygonViewPoint)

            {
                print("Your are INSDIE Subregion Species Area.")

                subregion.PolygonInMyCurrentLocation = polygon

            AppDelegate.getAppState().filterByRegionID = String(subRegionArray[i].id)+",subregion_code"
            AppDelegate.getAppState().save()
            AppDelegate.getAppState().IsSpeciesFoundInSubRegionPolygonArea = true
            AppDelegate.getAppState().save()
                return true
            }

            else

            {
            }
    }


    print("Your are out of Subregion Species Area.")
    subregion.PolygonInMyCurrentLocation = nil

    AppDelegate.getAppState().filterByRegionID = ""
    AppDelegate.getAppState().save()
    AppDelegate.getAppState().IsSpeciesFoundInSubRegionPolygonArea = false
    AppDelegate.getAppState().save()

return false
}



func formatSubRegionArray(singleElementInSubRegionArray: String) -> [CLLocationCoordinate2D]
{
    var subRegionComponents = singleElementInSubRegionArray.components(separatedBy: ",")
    var boundary = [CLLocationCoordinate2D]()

    for i in stride(from: 0, to: subRegionComponents.count, by: 2) {
        let first = subRegionComponents[i]
        let second = subRegionComponents[i + 1]
        boundary.append(CLLocationCoordinate2D(latitude: CLLocationDegrees(first)!, longitude: CLLocationDegrees(second)!))
    }

    return boundary
}


/*
 func format_subRegion_Array_Elements_To_sub_Elements(one_element_in_subRegionArray : String) -> [CLLocationCoordinate2D]

 {

 var boundary: [CLLocationCoordinate2D]

 var Boundary_points_in_string_format : [String]
 let Array_of_one_element_in_subRegionArray : [String] = one_element_in_subRegionArray.componentsSeparatedByString(",")


 Boundary_points_in_string_format = []

 for var i = 0 ; i <= Array_of_one_element_in_subRegionArray.count-1 ; i += 1

 {
 Boundary_points_in_string_format += [String(Array_of_one_element_in_subRegionArray[i]+","+Array_of_one_element_in_subRegionArray[i+1])]

 i = i+1

 }

 let  boundaryPointsCount = Boundary_points_in_string_format.count

 boundary = []

 for i in 0...boundaryPointsCount-1
 {

 let newArrayElement  = Boundary_points_in_string_format[i].componentsSeparatedByString(",")

 let myDouble1 = Double(newArrayElement[0])
 let myDouble2 = Double(newArrayElement[1])
 boundary += [CLLocationCoordinate2DMake(CLLocationDegrees(myDouble1!), CLLocationDegrees(myDouble2!))]

 }

 return boundary
}
*/

回答1:

This code is needlessly complex. Shockingly so, actually. I'm quite impressed how obfuscated this is. Here's my best attempt at recreating it:

func format(subRegion: String) -> [CLLocationCoordinate2D] {
    var subRegionComponents = subRegion.components(separatedBy: ",")

    let boundaries = stride(from: 0, to: subRegionComponents.count - 1, by: 2).map { i in
        let first = subRegionComponents[i], let second = subRegionComponents[i + 1]
        return CLLocationCoordinate(CLLocationDegrees(first)!, CLLocationDegrees(second)!)
    }

    return boundaries
}
  1. Swift's convention is to use lowerCamelCase for variable names, and CapitalCamelCase for types. Stick to it, please.
  2. Don't split a delcaration and defintion apart if you don't have to. Rather than var boundary: [CLLocationCoordinate2D] and boundary = [], just use var boundary = [CLLocationCoordinate2D]()
  3. Don't add redundant type annotations unless they actually add clarity rather than detract from it.
  4. Don't explicitly name things "array of ...". Just pluralize. Its type will be implicit.
  5. Don't manually subtract one when using the open range operator (...). Just use the closed range operator (..<). e.g. 0..<boundaryPointsCount instead of 0...boundaryPointsCount-1
  6. Don't use 0..<array.count when you can just use array.indices


回答2:

Index variables are constants by definition, you can't change them.

But, as you want to use the item plus item + 1 in the repeat loop just use stride:

typealias Array_of_one_element_in_subRegionArray = arr

for i in stride(from: 0, to: arr.count, by: 2) {
    Boundary_points_in_string_format += [String(arr[i] + "," + arr[i+1])] 
}


回答3:

Like I am seeing it, you are just incrementing i because you converted from the old for loop style. In the for in with enumerated you do not need to increment i since you already have all items with each is own number.

You do not need to increment i.

Since i is the number you get from enumerated().

let strings = ["Dog", "Cat", "Bird"]

for (i, string) in strings.enumerated() {
    print(i)
    print(string)
}

Output:

0
Dog
1
Cat
2
Bird

If you would not use enumerated() you would create an Int outside of the for, and then increment it. You can not change the item in one for loop.



标签: swift3 mapkit