17

I am trying to use the Lyft API with iOS 11 and Swift 4, and am receiving an error on the second line, which is

Overlapping accesses to 'urlComponents', but modification requires exclusive access; consider copying to a local variable.

I am unsure what this means, and how I can get around it. Any help is appreciated, thanks!

let queryItems = parameters
    .sorted { $0.0 < $1.0 }
    .flatMap { components(forKey: $0, value: $1) }
var urlComponents = URLComponents(url: mutableURLRequest.url!, resolvingAgainstBaseURL: false)
urlComponents?.queryItems = (urlComponents?.queryItems ?? []) + queryItems //error here
marosoaie
  • 2,352
  • 23
  • 32
John Harding II
  • 564
  • 1
  • 6
  • 20
  • 1
    I guess you need to set first to a local variable and then change it , try this: var urlComponents = URLComponents(url: mutableURLRequest.url!, resolvingAgainstBaseURL: false) var localVariable = urlComponents localVariable?.queryItems = (urlComponents?.queryItems ?? []) + queryItems , then assign it back like this urlComponents = localVariable – 3stud1ant3 Sep 09 '17 at 02:38
  • directly before- added in an edit – John Harding II Sep 09 '17 at 02:39
  • 3stud1ant3 that worked perfectly, would you like to submit as an answer so I can accept it? – John Harding II Sep 09 '17 at 02:41
  • This can also occur when you haven't unwrapped an optional instance variable. if you put mutableURLRequest in a Guard var statement it should resolve the compiler error as well. – aBikis Jan 09 '18 at 20:04

3 Answers3

32

I guess you need to set first to a local variable and then change it , try this:

var urlComponents = URLComponents(url: mutableURLRequest.url!, resolvingAgainstBaseURL: false) 
var localVariable = urlComponents 
urlComponents?.queryItems = (localVariable?.queryItems ?? []) + queryItems  
3stud1ant3
  • 3,586
  • 2
  • 12
  • 15
  • 1
    I believe you can eliminate the 4th line by changing the 3rd line to: `urlComponents?.queryItems = (localVariable?.queryItems ?? []) + queryItems` – rmaddy Sep 09 '17 at 03:18
6

In this case the problem is the overlapping access to an optional, so the easiest solution would be to unwrap urlComponents before mutating its queryItems:

if var urlComponents = URLComponents(url: mutableURLRequest.url!, resolvingAgainstBaseURL: false) {
    urlComponents.queryItems = (urlComponents.queryItems ?? []) + queryItems
    // ...
}
Martin R
  • 529,903
  • 94
  • 1,240
  • 1,382
2

Might not be directly related to the question details, but for anyone googling this error message, be aware that the error also happens on attempt to manipulate with data of ambiguous type (it is unclear if it is class or a struct at the moment of manipulation).

Example when this error might appear:

protocol: AnItemCapableToShowDetails {
    var isShowingDetails: Bool { get set }
}

class: DataItem, AnItemCapableToShowDetails {
   ...
   var isShowingDetails = false
}

class: SomeClass {
   func showDetails() {
       if let dataItem = itemsArray[index] as? AnItemCapableToShowDetails {
           ...
           dataItem.isShowingDetails = !dataItem.isShowingDetails // <- "Overlapping accesses..." error here
                                                                  // because that protocol might 
                                                                  // potentially be applied to a struct as well
       }
   }
}

Possible fix is to make it a class-only protocol, so that compiler is ensured that manipulations are always made with a class.

For before Swift 4:

protocol: AnItemCapableToShowDetails: class {
    var isShowingDetail: Bool { get set }
}

In Swift 4 and later also available (and is a preferred way of doing this):

protocol: AnItemCapableToShowDetails: AnyObject {
    var isShowingDetail: Bool { get set }
}
Vitalii
  • 4,267
  • 1
  • 40
  • 45