Swift - optional dates comparison - ios

I'm trying to implement code in swift which will give me the closest date from current date.
The thing is I want users to choose in maximum 3 dates, and every time he chooses the date is added to the array named "reminders"
Then I check how many items (max 3) are in this array (named: reminders), and store the particular date/ dates from the array using CoreData:
if addObjectView.reminders.count == 1 {
newobject.firstReminder = addObjectView.reminders[0]
}
if addObjecteView.reminders.count == 2 {
newobject.firstReminder = addObjectView.reminders[0]
newobject.secondReminder = addObjectView.reminders[1]
}
if addObjectView.reminders.count == 3 {
newobject.firstReminder = addObjectView.reminders[0]
newobject.secondReminder = addObjectView.reminders[1]
newobject.thirdReminder = addObjectView.reminders[2]
}
Then I want to implement code to check first if the first/second/thirdReminder from CoreData is nil, and if it's not then compare it to current date. If it is 'larger' then set String from this date as label. But I want also to compare date from first/second/thirdReminder between themselves or somehow make sure that the firstReminder will always be earlier than second and so on.
I don't know if it is that hard, but I'm trying to figure it out and I'm stuck.

You should use the nil coalescing operator for this purpose.
The nil coalescing operator (a ?? b) unwraps an optional a if it contains a value, or returns a default value b if a is nil. The expression a is always of an optional type. The expression b must match the type that is stored inside a.
Source - developer.apple.com
You could get the reminder's date, stored in myOptionalDate, and check if it is nil. If it is, then we will do
0 > NSDate().timeIntervalSince1970
which will always be false. If it isn't nil, we can do the equivalent of
myOptionalDate!.timeIntervalSince1970 > NSDate().timeIntervalSince1970
which will tell you if you if the label should be added
if((myOptionalDate?.timeIntervalSince1970 ?? 0) > NSDate().timeIntervalSince1970){
//add the label
}
Which is shorthand for
var myInterval = 0
if(myOptionalDate != nil){
myInterval = myOptionalDate!.timeIntervalSince1970
}
if(myInterval > NSDate().timeIntervalSince1970)
Also, although this doesn't have to do with the question, depending on how your code is formatted, you shouldn't have to use if statements to check how many reminders there are
By default, newobject.firstReminder, newobject.secondReminder, and newobject.thirdReminder will (I'm assuming) be nil. So, you could just change all of your example code to
let originalReminders = addObjectView.reminders
newobject.firstReminder = originalReminders.count > 0 ? originalReminders[0] : nil
newobject.secondReminder = originalReminders.count > 1 ? originalReminders[1] : nil
newobject.thirdReminder = originalReminders.count > 2 ? originalReminders[2] : nil
if the default value isn't nil, you could simply replace nil in the above code with your default value

Related

Count Annotations on MapView in Swift

After completing a loop that places annotations on a map from an array, I want to count the number of annotations.
My code as follows:
let anCount = self.mapView.annotations?.count
if (anCount > 1) {
//do something
}
gives error:
Value of optional type 'Int?' must be unwrapped to a value of type
'Int'
The fixit suggestions yield other errors. What is the correct way to count the number of annotations for the map.
Thanks for any suggestions.
You have to unwrap the optional, e.g. with if let, which you can then combine with the > 1 test in a single if statement:
if let anCount = mapView.annotations?.count, anCount > 1 {
//do something
}
But annotations isn't an optional (at least in current iOS versions), so you'd probably just do:
let anCount = mapView.annotations.count
if anCount > 1 {
//do something
}

sort an array by comparing a string value swift [duplicate]

This question already has answers here:
Sorting array alphabetically with number
(8 answers)
Closed 4 years ago.
I'm trying to sort an array by comparing a string value from two items, the values of the property are a number but of type String. How can I convert them to Int and check which is greater. Current code looks like this.
libraryAlbumTracks = tracks.sorted {
$0.position!.compare($1.position!) == .orderedAscending
}
but values like "13" come before "2" because it's a string. I tried to cast the values to Int but because they are optional, I get the error that operand ">" cannot be applied to type Int?
Please how can I go around this in the sorted function?
Provide the numeric option when using compare. This will properly sort strings containing numbers and it also works if some of the string don't actually have numbers or the strings have a combination of numbers and non-numbers.
libraryAlbumTracks = tracks.sorted {
$0.position!.compare($1.position!, options: [ .numeric ]) == .orderedAscending
}
This avoids the need to convert the strings to Int.
Note: You should also avoid force-unwrapping position. Either don't make them optional if it's safe to force-unwrap them, or safely unwrap then or use ?? to provide an appropriate default when comparing them.
libraryAlbumTracks = tracks.sorted {
guard let leftPosition = $0.position,
let leftInt = Int(leftPosition),
let rightPosition = $1.position,
let rightInt = Int(rightPosition) else {
return false
}
return leftInt > rightInt
}

Cannot assign value of type 'String?' to type 'Int'

I am getting the error message Cannot assign value of type 'String?' to type 'Int'
I have browsed through other questions like this but it still shows the error.
if sunscreenName.text != nil && reapplyTime.text != nil {
sunscreen = sunscreenName.text!
reApplyTime = reapplyTime.text
//Some sort of message such as Progress hud
}
Thanks in advance!
I got your problem, actually what happens here Swift is is type safe langauge
So what you are doing is is to store a String value in Int which will not happen automatically you need to convert it to Int
like this
Int(sunscreenName.text)
But there is a catch there not all string are convertible to Int type, fo e.g.
let name = "roshan"
if you try to convert it to Int it will give you a nil
let a = Int(name)
So its better you do a optional Binding here provided by Swift
if let sunValue = Int(sunscreenName.text),let reApplyValue = Int(reapplyTime.text) {
sunscreen = sunValue
reApplyTime = reApplyValue
}
I recommend reading through The Swift Programming Language to get a better understanding of Swift and its fundamental concepts, since this question is fairly basic.
You make several mistakes:
if sunscreenName.text != nil && reapplyTime.text != nil {
This is wrong. In Swift, if you plan to use the value later, you should use if let rather than comparing to nil. Comparing to nil leaves the values optional, but if let unwraps them. So, do this instead:
if let sunscreenText = sunscreenName.text, let reapplyText = reapplyTime.text {
Now you have the sunscreenText and reapplyText variables, which are typed String, not String? (i.e. they are not optional).
Now, there's these two lines.
sunscreen = sunscreenName.text!
reApplyTime = reapplyTime.text
You don't say which one is giving the error, but the issue is the same in either case. First, use our unwrapped sunscreenText and reapplyText variables instead of sunscreenName.text! and reapplyTime.text. Next, if one of these is meant to be an Int instead of a String, cast it. Swift is not like JavaScript, in that it won't automatically convert values from one type to another, so if something is a string and we need an integer, we have to convert it ourselves.
(assuming reapplyTime was the line that was giving the error:)
if let reapplyInt = Int(reapplyText) {
reapplyTime = reapplyInt
}
The reason we have to unwrap is because Int(String) can return nil if the string is something that can't be converted to an integer. Alternately, we could just provide a default value:
reapplyTime = Int(reapplyText) ?? 0 // sets to 0 if it can't parse the string as an integer

How to find first non-zero element of an Array?

Is there a way to grab the first non-zero element from an array of numbers?
I have an Array with many zeros at the beginning and I need only the first item that is not a zero.
For example:
let array = [0,0,0,0,25,53,21,77]
based on the above, the result should be 25.
What is the good way to achieve it?
You could get it like this:
let array = [0,0,0,0,25,53,21,77]
let firstNonZero = array.first { element -> Bool in
return element != 0
}
Or as a shorter version:
let firstNonZero = array.first(where: { $0 != 0 })
Note that firstNonZero would be an optional Int, so in case of array contains only zeros, firstNonZero would be nil.
Aside bar note: If you were wondering why to use first(where:) instead of filter(_:).first, you could check this question:
What is the difference between filter(_:).first and first(where:)?

Assigning default values if NULL

I have an MVC app where a user can select company benfits, there are 10 different benefits and they can have none up to all 10 of these. In my view I have the ten listed with radio buttons to indicate whether they are required or not. There is also a calculation performed in the controller that adds all the values together to give a total.
As an example in my controller -
newuser.LifeAssurance.LifeAssuranceRequired = viewModel.LifeAssuranceRequired;
newuser.LifeAssurance.LifeAssuranceSchemeName = viewModel.LifeAssuranceSchemeName;
newuser.LifeAssurance.LifeAssuranceProviderName = viewModel.LifeAssuranceProviderName;
newuser.LifeAssurance.LifeAssuranceBenefitLevel = viewModel.LifeAssuranceBenefitLevel;
newuser.LifeAssurance.LifeAssuranceEmployerCost = viewModel.LifeAssuranceEmployerCost;
newuser.LifeAssurance.LifeAssuranceEmployeeCost = viewModel.LifeAssuranceEmployeeCost;
Since the user may decide not to choose this benefit is it possible to assign the cost as 0 if they have not made a selection in the view model? Can I check if it's null and add 0 in that case?
You can use the ?? operator (see here)
use it like this:
string someString = null;
string someOtherString = someString ?? "0";
if someString(or any other object) is not null use it, else use whatever is on the right of the ?? operator.
Maybe set your values as nullable by add ? to type, and then you can check it is null by:
var someValue = (nullableValue.HasValue) ? nullableValue.Value : 0;

Resources