I have a dictionary that a fetch request is returning. This dictionary is then made in to an array of dates from [String: NSDate]. This dictionary has a value that is [:]. I cannot do anything to remove it. Can anyone help because I have spent two nights trying everything.
let results = try managedObjectContext.executeFetchRequest(fetchRequest) as! [[String:NSDate]]
print("results \(results)")
dates = results.map { $0["savedTime"]! as NSDate }
This failed due to the savedTime Key being nil
print result is
[["savedTime": 2016-07-19 23:00:00 +0000], [:]]
This construct $0["savedTime"]! is wrong. Putting the ! on the object means you know that the object will always be there, but it isn't always there. You are lying to the compiler so it is crashing. Try removing the !.
Also, putting the as NSDate is unnecessary because you already told the compiler that the values are NSDates in the line above. Lastly, since not all the dictionaries have the correct key, you need to remove any that don't. There are a couple of ways to do that, one would be to filter out the nils. Another is to use flatMap which converts and filters out nils at the same time.
Then you end up with the below.
let results = try managedObjectContext.executeFetchRequest(fetchRequest) as! [[String:NSDate]]
print("results \(results)")
dates = results.flatMap { $0["savedTime"] }
I'm worried though that even the above, although it compiles and runs, might not be what you really need. The array of dictionaries is a rather odd thing to be pulling out of a managedObjectContext...
Related
I have an array with 3 elements and want to take the first one and the last one elements.
let array = ["a", "b", "c"]
let first: String = array.first!
let last: String = array.last!
SwiftLint mark a force unwrap as a warning. Can I avoid a forced unwrapping when asking about the first and the last elements for a well known (defined) arrays?
I don't want to use a default values like in an example below
let first :String = array.first ?? ""
Edit:
Why am I asking about it? Because, I would like to avoid an warnings from the SwiftLint when using a forced unwrapping when asking for a first and a last element of an array which was defined by a literal and has enough elements to be sure that there is the first and the last element.
Edit 2:
I have found a name for what I was looking for. It's called Static-Sized Arrays. Static-Sized Arrays discussion stoped in 2017 and there is no chance to use it.
Try with index:
let first = array[0]
let last = array[array.count - 1]
Why am I asking about it? Because, I would like to avoid an warnings
from the SwiftLint when using a forced unwrapping when asking for a
first and a last element of an array which was defined by a literal
and has enough elements to be sure that there is the first and the
last element.
You can't really avoid to unwrap optional value, so if you only need it for two cases extensions can help here.
extension Collection {
func first() -> Element {
guard let first = self.first else {
fatalError() // or maybe return any kind of default value?
}
return first
}
}
let array = [1, 2]
array.first() // 1
And if it need to be only in one swift file you can place this code in that file and mark extensions with private keyword.
Can I avoid a forced unwrapping when asking about the first and the last elements for a well known (defined) arrays?
No you don't have to worry about it for a fixed array , actually the optional attachment for the properties first and last is designated to avoid crashes for an empty arrays
in a practice problem I was asked to print out all elements that are not nil in an array of string, and I realize
for case let name? in names{
print(name)
}
would do the job. But isn't it counter-intuitive?
In the snippet, I read it as "for every element (with actual value or nil)that is in names", but in fact it should be "for every element (actual value)that is in names".
Can anyone help me to make sense of the snippet?
You want to know why this code:
let names = ["b", nil, "x"]
for case let name? in names {
print(name)
}
Produces this output:
b
x
You are wondering what happens to the nil.
The answer is the "Optional Pattern" found in the Language Reference:
The optional pattern provides a convenient way to iterate over an
array of optional values in a for-in statement, executing the body of
the loop only for non-nil elements.
The case keyword is vital. It changes the nature of the for loop significantly. As you can see from this complier error, name? inside the loop is not an optional at all.
Think of the ? as an operator that removes the optionality of name. If the assignment would result in nil, that iteration of the loop does not happen, and the next iteration starts.
Notice that without the case you do not get the same behavior at all.
This:
for name in names {
print(name)
}
Will get this output:
Optional("b")
nil
Optional("x")
And that neither of these work at all.
You can use filter with conditional and then print the result like this:
let nameNotNil = names.filter{$0 != nil} //filter all values diferent nil
print(nameNotNil) // can be nil if any didnt has strings
I want to convert the results from my Realm data into Int.
Here is an example of how I want to use this.
let results = realm.objects(Data.self)
print(results)
However the result is type Results<Data> and cannot be converted into a Int but the results is an Int.
Just to be clear I want an array of Int from my results
You can simply use Array(realm.objects(RealmType.self)), which will convert the Results<RealmType> instance into an Array<RealmType>.
However, there are other serious flaws with your code. First of all, neither of the last two lines will compile, since firstly realm.objects() accepts a generic input argument of type Object.Type and Data doesn't inherit from Object. You can't directly store Data objects in Realm, you can only store Data as a property of a Realm Object subclass.
Secondly, myArray[results] is simply wrong, since results is supposed to be of type Results<RealmType>, which is a collection, so using it to index an Array cannot work (especially whose Element type is different).
It appears that based on the number of results from the database, you want to select an object from the array.
You can get the number of items in an array with .count. Be certain that an object exists at the specified index in the array, or your application will crash!
let numberOfResults = results.count
if myArray.count > numberOfResults {
let object = myArray[numberOfResults]
print(object)
}
I need to retrieve a setting (with Swift):
var highScoreNumber: NSInteger = 0
var returnValue: [NSInteger]? = NSUserDefaults.standardUserDefaults().objectForKey("food") as? [NSInteger]
if (returnValue != nil) {
highScoreNumber = returnValue as NSInteger
}
I tried this and other variations of the code and I always get
'NSInteger?' not convertible to 'NSInteger'
This is my first foray into Swift, so
Am I missing something simple in the conversion?
Is there a better way to retrieve an NSInteger from settings?
When converting a nullable value to a non-nullable one, there are many good options to choose from.
But in your case, you have two issues. One is the array you’re fetching from NSUserDefaults is an array of integers, so you need to decide which one you want from that array.
If it’s the first one you want, you can use the first property. You can use optional chaining to get it. And since it’s a high score, you probably want to default to zero if it’s not present.
Here’s that in one line:
let returnValue = NSUserDefaults.standardUserDefaults().objectForKey("food") as? [Int]
let highscore = returnValue?.first ?? 0
Things to note about the above: there’s no need to give the type to the left of the = if the type is unambiguously determined by what lies to the right of the =. And it’s better to prefer Int over NSInteger.
The returnValue?.first says “if returnValue is nil, then nil, else the value of first (which, itself, returns nil if the array is empty).” The ?? says “if the left of ?? is nil, then the value on the right of nil, else the unwrapped value from the left”.
That said – do you really mean to store an array? Or do you really just want to store a single integer in the defaults and then get that out directly?
let highscore = NSUserDefaults.standardUserDefaults().integerForKey("food")
// and elsewhere in your code, when saving
NSUserDefaults.standardUserDefaults().setInteger(highscore, forKey: "food")
(integerForKey already returns a 0 default when not present rather than an optional, so no need for any unwrapping)
I am not totally sure if this the right place to post this, as it is more a pitfall I have found than a question I would ask. (Although I would be very interested if someone could explain the reason why this happens.)
So in my Swift iOS-app I had to use Objective-C Arrays for sorting. I knew for a fact that the NSMutableArray called results would contain only MyObjects. Thus, after sorting I cast it to [MyObject] like this to save it in the variable myArrayVar : [MyObject].
myArrayVar = (results as NSArray) as [MyObject]
This worked fine until I tested it on a release build. There it crashed. What I had to do to fix the crash was this:
if let results = results as Any as? NSArray {
if let results = results as? [MyObject] {
myArrayVar = results
} else { NSLog("the impossible happened.") }
} else { NSLog("the impossible happened.") }
Now we can see that this version cannot crash when the casting goes wrong whereas the first version would. However, the cast does not go wrong as I could verify by never seeing the log message.
So what might be the difference at runtime between these two versions of type casting? Whatever it is I have the feeling it might be a pitfall for others as well.