after upgrading to new version of Xcode/swift i am getting error "Ambiguous use of subscript before was work well but now i am getting this error
my code for search in my data
#IBAction func searchB(sender: UITextField) {
dataSecond = []
if sender.text == "" {
search = false
self.reload()
} else {
for i in data {
if (i["name"] as! String!).lowercaseString.findInString(sender.text!) { //Here is the error in this if condition
dataSecond.addObject(i)
}
}
search = true
self.reload()
}
Swift 2.2 is rather strict about types, much more strict than the previous versions. What was implicit before has now to be explicit.
Use safe unwrapping and downcasting and it should work:
if let senderText = sender.text {
for i in data {
if let name = i["name"] as? String {
if name.lowercaseString.findInString(senderText) {
dataSecond.addObject(i)
}
}
}
}
Related
I am having trouble analyzing the results given by the callback of GMSPlacesClient findAutocompletePredictionsFromQuery:, which is a GMSAutocompletePrediction array.
The app will crash on let searchResultsWayPoints = finalResults.map ,
stating
Precondition failed: NSArray element failed to match the Swift Array Element type
Expected GMSAutocompletePrediction but found GMSAutocompletePrediction
func getGoogleWayPoint(text: String) -> Promise<[GoogleWayPoint]> {
return Promise<[GoogleWayPoint]> { resolver in
if text.isEmpty {
resolver.fulfill([])
return
}
placesClient.findAutocompletePredictions(fromQuery: text, filter: filter, sessionToken: sessionToken) { (results, error) in
if let error = error {
dprint(error.localizedDescription)
resolver.fulfill([])
return
}
guard let finalResults = results else {
dprint("can't found results")
resolver.fulfill([])
return
}
let searchResultsWayPoints = finalResults.map {
GoogleWayPoint(id: $0.placeID, address: $0.attributedFullText.string)
}
resolver.fulfill(searchResultsWayPoints)
}
}
}
Any help would be appreciated. Thank you.
So I have solved this problem, but I did not fix anything, since it is from the GooglePlaces framework.
In order to solve this, simply make results as results:[Any]? at the callback.
Then, at guard let, safely convert it to [GMSAutocompletePrediction].
Here is the complete code
func getGoogleWayPoint(text: String) -> Promise<[GoogleWayPoint]> {
return Promise<[GoogleWayPoint]> { resolver in
if text.isEmpty {
resolver.fulfill([])
return
}
placesClient.findAutocompletePredictions(fromQuery: text, filter: filter, sessionToken: sessionToken) { (results: [Any]?, error) in
if let error = error {
dprint(error.localizedDescription)
resolver.fulfill([])
return
}
guard let finalResults = results as? [GMSAutocompletePrediction] else {
dprint("can't found results")
resolver.fulfill([])
return
}
let searchResultsWayPoints = finalResults.map {
GoogleWayPoint(id: $0.placeID, address: $0.attributedFullText.string)
}
resolver.fulfill(searchResultsWayPoints)
}
}
}
func reloadFriendList() {
var query = PFQuery(className:"userFriendClass")
query.whereKey("username", equalTo:user!.username!)
query.findObjectsInBackgroundWithBlock {
(objects: [PFObject]?, error: NSError?) -> Void in
if error == nil {
for object in objects! {
self.friendList = object["friends"] as! [String]
print(self.friendList)
self.reloadTableView()
}
} else {
// Log details of the failure
print("Error: \(error!) \(error!.userInfo)")
}
}
}
i want to save object["friends"] that is an array from parse with usernames into
var friendList = [String]()
but i get the error: "fatal error: unexpectedly found nil while unwrapping an Optional value",
when the array is empty which means the user doesn't have any friends yet it works fine when the user have at least 1 or more friends.
You need to have your code ready to handle nil cases and cases where "objects" is an empty array.
If this were my code, I would do something like:
for object in objects {
if let friendList = object["friends"]
{
self.friendList = friendList
} else {
// make sure that your class's `friendList` var is declared as an optional
self.friendList = [String]()
}
}
Since objects is optional and may be nil, you need to unwrap it safely. One way to do that is to use the nil coalescing operator to unwrap it or to substitute an empty array if objects is nil. You can use it again to safely unwrap the list of friends:
for object in objects ?? [] {
self.friendList = (object["friends"] as? [String]) ?? []
You can also use optional binding if let to safely unwrap things:
if let unwrappedObjects = objects {
for object in unwrappedObjects {
if let friends = object["friends"] as? [String] {
self.friendsList = friends
} else {
// no friends :-(
self.friendsList = []
}
}
}
Hi I'm trying to fix SugarRecord a great way to use CoreData and iCloud.
I'm getting this error above with the following method:
public func find(finder: SugarRecordFinder) -> SugarRecordResults
{
let fetchRequest: NSFetchRequest = SugarRecordCDContext.fetchRequest(fromFinder: finder)
var objects = [NSManagedObject]()
do{
objects = try self.contextCD.executeFetchRequest(fetchRequest) as! [NSManagedObject]
}
catch
{
}
if objects == nil {
objects = [NSManagedObject]()
}
return SugarRecordResults(results: SugarRecordArray(array: objects), finder: finder)
}
The error is on the line - if objects == nil {
Though after searching the net I couldn't find a way to fix this. Thank you if you can help.
executeFetchRequest return always an array. If nothing could be found the array is empty.
Just delete
if objects == nil {
objects = [NSManagedObject]()
}
A better syntax is
public func find(finder: SugarRecordFinder) -> SugarRecordResults
{
let fetchRequest: NSFetchRequest = SugarRecordCDContext.fetchRequest(fromFinder: finder)
do {
let objects = try self.contextCD.executeFetchRequest(fetchRequest) as! [NSManagedObject]
return SugarRecordResults(results: SugarRecordArray(array: objects), finder: finder)
}
catch let error as NSError {
// do error handling
return SugarRecordResults()
}
}
Currently I'm working on my new App written with Swift 2.0. Today I faced two strange errors in Xcode beta 5. I'd love if someone with a previous beta version of Xcode can confirm if I'm right or not. I also could misunderstand something, so I'll appreciate any feedback.
Here is some example code that made me struggle a while:
// Frist bug
protocol SomeProtocol {
var someArray: [String] { get set } // #1 bug
}
extension SomeProtocol {
func someFunction(someString: String) {
self.someArray.append(someString) // #1: Immutable value of type '[String]' only has mutating members named 'append'
}
}
// Second bug
protocol SomeInterfaceProtocol {
var someBool: Bool { get set } // #2 bug
}
class SomeClass: SomeInterfaceProtocol {
var someBool: Bool = false
func returnInterface() -> SomeInterfaceProtocol {
return self
}
}
let someInstance = SomeClass()
// can't set the value
someInstance.returnInterface().someBool = true // #2: Cannot assign to property: function call returns immutable value
The first error can be solved if you add the modifier mutating before the extension func declaration like this:
mutating func someFunction(someString: String) {
I suspect that's a change in the language.
The other one puzzles me as well. At least, here's a work-around:
var c = someInstance.returnInterface()
c.someBool = true
I think the second one isn't a bug as well for the same reason that you can't modify an item in a dictionary directly, or that you can't change elem in for elem in array { ... }.
Something has to be saved to be able to change it. Because you're returning the protocol type, the compiler can't know whether it's a struct or a class, whereas if it's a struct the operation of changing it would have no effect because it's not persisted in any way and structs aren't passed by reference. That's why Thomas' workaround works. Maybe it'll work too if returnInterface returned a class instance, instead of the protocol type.
EDIT: Just tried it out: Indeed it works either if you return SomeClass instead of SomeInterfaceProtocol or if you change the protocol to a class protocol, as it can't be a struct
protocol SomeInterfaceProtocol : class {
var someBool: Bool { get set }
}
class SomeClass: SomeInterfaceProtocol {
var someBool: Bool = false
func returnInterface() -> SomeInterfaceProtocol {
return self
}
}
or
protocol SomeInterfaceProtocol {
var someBool: Bool { get set }
}
class SomeClass: SomeInterfaceProtocol {
var someBool: Bool = false
func returnInterface() -> SomeClass {
return self
}
}
both work
I am trying to print out the value "username" from my coredata entity.
var request = NSFetchRequest(entityName: "Users")
request.returnsObjectsAsFaults = false
var results = context.executeFetchRequest(request, error: nil)
if (results?.count > 0) {
for result: AnyObject in results! {
println(result.username)
}
}
The line println(result.username) is giving me a compile error of 'AnyObject' does not have a member named 'username'.
You have to cast the array of managed object to the correct type:
for result in results! as [Users] {
println(result.username)
}
This assumes that you have created a managed object subclass for the "Users" entity.
You should also distinguish whether executeFetchRequest() returned nil
(i.e. the fetch request failed), or 0 (i.e. no objects found),
and use the error parameter:
var error : NSError?
if let results = context.executeFetchRequest(request, error: &error) {
if (results.count > 0) {
for result in results as [Users] {
println(result.username)
}
} else {
println("No Users")
}
} else {
println("Fetch failed: \(error)")
// Handle error ...
}
Update for Swift 2/Xcode 7 with try/catch error handling:
do {
let results = try context.executeFetchRequest(request) as! [Users]
if (results.count > 0) {
for result in results {
print(result.username)
}
} else {
print("No Users")
}
} catch let error as NSError {
// failure
print("Fetch failed: \(error.localizedDescription)")
}
Note that the forced cast as! [Users] is acceptable here.
The returned objects are always instances of the corresponding class as configured in the Core Data model inspector, otherwise you have
a programming error which should be detected early.
Martin's answer definitely lets you access the properties of your object, but the cast is forced. Like it or not, Swift's strong type system is the future. When returning results from a fetch request, you might consider testing for the type.
func executeFetchRequestT<T:AnyObject>(request:NSFetchRequest, managedObjectContext:NSManagedObjectContext, error: NSErrorPointer = nil) -> [T]? {
var localError: NSError? = nil
if let results:[AnyObject] = managedObjectContext.executeFetchRequest(request, error: &localError) {
if results.count > 0 {
if results[0] is T {
let casted:[T] = results as [T]
return .Some(casted)
}
if error != nil {
error.memory = NSError(domain: "error_domain", code: 0, userInfo: [NSLocalizedDescriptionKey: "Object in fetched results is not the expected type."])
}
} else if 0 == results.count {
return [T]() // just return an empty array
}
}
if error != nil && localError != nil {
error.memory = localError!
}
return .None
}
Using this approach you can type your results and get an error if the type is incorrect.
var fetchError:NSError? = nil
if let results:[Users] = executeFetchRequestT(fetchRequest, managedObjectContext: managedObjectContext, error: &fetchError) {
for user in results {
// access the results with confidence of the correct type
}
} else {
// should have an error condition, handle it appropriately
assertFailure("something bad happened")
}
Change your for loop to this
for result: AnyObject in results! {
if let user: AnyObject = result.valueForKey("username") {
println(user)
}
}
The fix is using valueForKey("String")