Since the switch to Swift 3.0, and along with it the change of NSDate to Date, the class no longer conforms to the NSCopying protocol.
In Swift 2, this was valid:
let newDate = oldDate.copy()
But now returns a compiler error.
With this being the case, what is the best way to duplicate a Date object?
let newDate = Date(timeIntervalSince1970: oldDate.timeIntervalSince1970)
This will do the trick, but it doesn't seem particularly elegant. And it is potentially (theoretically) susceptible to loss of precision as a TimeInterval is a Double (and we have no way of confirming that a Date object internals uses - or always will use - a Double).
Answering my own question as I figured it out before I finished typing it. Hopefully it will help someone else.
Date in Swift 3 is now a struct, not a class. Which is a value type. Which means that it does not need to be 'copied', simply assigning it to a new variable will copy the data:
let newDate = oldDate
Related
I found a bug in my code that is caused by NSDecimalNumber.notANumber.intValue returning 9, while I would expect NaN (as floatValue or doubleValue return). Does anybody know why?
Like mentioned by Joakim Danielson and noted in the Apple Developer Documentation
... Because numeric types have different storage capabilities, attempting to initialize with a value of one type and access the value of another type may produce an erroneous result ...
And since Swift's Int struct cannot represent NaN values, you get this erroneous result.
Instead you could use Int's Failable Initialiser init(exactly:) that converts your NSDecimalNumber to an Int? that will either contain it's value or be nil if it is not representable by an Int.
let strangeNumber = NSDecimalNumber.notANumber // nan
let integerRepresentation = Int(exactly: strangeNumber) // nil
i just started learning Swift and trying to make an assignment for iOS.
what i have is 4 categories of keywords, for example:
CategoryX: hello, bye, good, bad
CategoryY: rain, sun
CategoryZ: sun, hello, what, rain
CategoryV: yes, no, bad, music, song, note
what i want is to compare this categories with each other and the result will give me the keywords that are in the choosen categories.
for example if i choose to compare all the categories, the results will be: null
(because there is no keyword that appear in all categories)
but if i choose X and Z, then the result will be: hello
if Y and Z then its: sun, rain
I’m not asking from anyone to write me the code (but ofc would be nice if someone gave me a headstart), i just want little explanation of how to deal with this problem and what to use to do it the right way, can someone shed some light?
thank you
I’m not asking from anyone to write me the code (but ofc would be nice if someone gave me a headstart), i just want little explanation of how to deal with this problem and what to use to do it the right way, can someone shed some light?
Okay, without giving the answer away, here’s a hint about how to deal with the problem., to give you a head start.
Doesn't this assignment make you think about sets? Remember those Venn diagrams you had to make in high school? Remember the idea of the intersection of sets? Think about that. Think about sets. Hmmm... Swift has a Set struct...
If you follow up that idea, and research what a Set is in Swift, you’ll see what to do.
Had fun writing it so I post it here. If you aren’t finished by now then look at the result and learn from it(my motto).
I expect you to learn .forEach, .map, .filter, guard let and optional subscript, since you skipped the easy answer with Sets. Oh don’t forget closures and how they strongly capture.
func compare(dicts: [[String]]) -> [String] {
var result = [String: Int]()
dicts.forEach { arg0 in
guard let priorResult = result[arg0.key] else {
result[arg0.key] = arg0.value
return
}
result[arg0.key] = priorResult + arg0.value
}
return result.filter{ arg0 in return arg0.value == dicts.count }.map{ return $0.key }
}
.map, forEach and .filter call for every item in the collection(for every key-value pair in a dictionary) thegiven closure.
.map returns an array of what is returned inside map.
.filter returns an array of items for which the closure returned true and so filtering out the items for which the closure returned false.
.forEach is an alternative to a for-loop.
result counts every occurance of a string.
.filter returns true for the strings which occured inside every dict.
.map maps the dictionary’s keys to a simple [String] array.
You can try
let set1 = Set(["123","456","789"])
let set2 = Set(["123","456"])
let set3 = Set(["123"])
let res12 = set1.intersection(set2) // ["123","456"]
let res123 = set1.intersection(set2).intersection(set3) // ["123"]
Objective C:
NSInteger x = // some value...
NSString* str = [NSString stringWithFormat:#"%d", (int)x];
// str is passed to swift
Swift:
let string:String = str!
let x = Int32(string)! // crash!
Sorry for the disjointed code, this is from a crash reported in a large existing codebase. I don't see how it's possible for the int->string->int32 conversion to fail. NSInteger can be too big for int32, but I would expect the explicit (int) to prevent that case (it will give the wrong value, but still shouldn't crash).
I have been unable to reproduce this, so I'm trying to figure out if my understanding is completely wrong.
Edit: obviously it is theoretically possible for it to return nil in the sense that the spec says so. I'm asking if/how it can in this specific situation.
Since you are using Int32, the initializer can return nil if the value supplied to it is out of the range Int32 can take. In your specific case this can easily happen, since as the documentation of NSInteger states, it can take 64bit values in 64bit applications (which is the only supported configuration since iOS11).
The documentation of Int32.init(_:String) clearly states that the cases when the failable initializer can fail:
If description is in an invalid format, or if the value it denotes in
base 10 is not representable, the result is nil. For example, the
following conversions result in nil:
Int(" 100") // Includes whitespace
Int("21-50") // Invalid format
Int("ff6600") // Characters out of bounds
Int("10000000000000000000000000") // Out of range
I am receiving a creation date for an object in a database as milliseconds (# of milliseconds since epoch or whatever) and would like to convert it to/from a string in Swift!
I think I'd need a data type of CUnsignedLong?
I am trying something like this but it outputs the wrong number:
var trial: CUnsignedLong = 1397016000000
println(trial) //outputs 1151628800 instead!
I'm guess this is the wrong data type so what would you all advise in a situation like this?
In Java I was using long which worked.
Thanks!
func currentTimeMillis() -> Int64{
let nowDouble = NSDate().timeIntervalSince1970
return Int64(nowDouble*1000)
}
Working fine
On 32-bit platforms, CUnsignedLong is a 32-bit integer, which is not large
enough to hold the number 1397016000000. (This is different from Java, where
long is generally a 64-bit integer.)
You can use UInt64 or NSTimeInterval (a type alias for Double), which is what the
NSDate methods use.
The first definition below produces the warning in the title when compiled with f# 3.0 and the warning level set to 5. The second definition compiles cleanly. I wondered if someone could please explain just what the compiler worries I might accidentally mutate, or how would splitting the expression with a let clause help avoid that. Many thanks.
let ticks_with_warning () : int64 =
System.DateTime.Now.Ticks
let ticks_clean () : int64 =
let t = System.DateTime.Now
t.Ticks
I cannot really explain why the compiler emits this warning in your particular case - I agree with #ildjarn that you can safely ignore it, because the compiler is probably just being overly cautious.
However, I can give you an example where the warning might actually give you a useful hint that something might not go as you would expect. If we had a mutable struct like this:
[<Struct>]
type Test =
val mutable ticks : int64
member x.Inc() = x.ticks <- x.ticks + 1L
new (init) = { ticks = init }
Now, the Inc method mutates the struct (and you can also access the mutable field ticks). We can try writing a function that creates a Test value and mutates it:
let foo () =
let t = Test(1L)
t.Inc() // Warning: The value has been copied to ensure the original is not mutated
t
We did not mark the local value t as mutable, so the compiler tries to make sure the value is not mutated when we call Inc. It does not know whether Inc mutates the value or not, so the only safe thing is to create a copy - and thus foo returns the value Test(1L).
If we mark t as mutable, then the compiler does not have to worry about mutating it as a result of a call and so it does not give the warning (and the function returns Test(2L)):
let foo () =
let mutable t = Test(1L)
t.Inc()
t
I'm not really sure what is causing the warning in your example though. Perhaps the compiler thinks (as a result of some intermediate representation) that Ticks operation could mutate the left-hand-side value (System.DateTime.Now and t respectively) and it wants to prevent that.
The odd thing is that if you write your own DateTime struct in F#, you get a warning in both cases unless you mark the variable t as mutable (which is what I'd expect), but the behaviour with standard DateTime is different. So perhaps the compiler knows something about the standard type that I'm missing...