1) I'm using a variable as the first argument in UIView.animateWithDuration like so:
var theDelay: Float = 1.0
UIView.animateWithDuration( theDelay, animations: {
cell.frame.origin.y = 0
})
and Xcode6 (Beta 3) is giving me a build error: 'Missing argument for parameter 'delay' in call'.
When I don't use a variable, the function works just fine. I'd like to tweak the variable (as this code is within a loop) when I discovered this issue.
2) Alternatively, I could skip using a variable and include the calculation in-line:
UIView.animateWithDuration( indexPath.row * 1.0, animations: {
cell.frame.origin.y = 0
})
but I am getting the same error 'Missing argument for parameter 'delay' in call'.
What am I doing wrong here?
The error message is misleading. The first parameter of animateWithDuration()
has the type NSTimeInterval (which is a Double), but you pass a Float argument.
Swift does not implicitly convert types.
Changing the variable definition to
let theDelay = 1.0
or an explicit conversion
UIView.animateWithDuration(NSTimeInterval(indexPath.row), animations: {
cell.frame.origin.y = 0
})
should solve the problem.
In Swift 3 this would be
let theDelay = TimeInterval(indexPath.row)
UIView.animate(withDuration: theDelay, animations: {
cell.frame.origin.y = 0
})
I also got this error from a totally unrelated error in the animations block; I was already passing in a valid NSTimeInterval. It had nothing to do with the delay parameter, so the error it was showing me was wrong and had me going in circles for a while.
So make sure you don't have any errors inside the animations block.
UIView.animateWithDuration(interval, animations: { () -> Void in // compiler will complain about this line missing a parameter
// some code
// some code with a syntax error in it, but Xcode won't show the error
// some code
})
Actually Swift is typed language and it need to pass same type arguments as defined
There is no implicit cast in swift.
As animateWithDurationin decleration
class func animateWithDuration(duration: NSTimeInterval, animations: (() -> Void)!) // delay = 0.0, options = 0, completion = NULL
has parameter type of NSTimeInterval which is declared as double if you see its declaration
typealias NSTimeInterval = Double
So it need Double parameter value not Float value.
When you call second timeas in your code than swift is using type interfrence i.e it is automatically defining(not convertting float to double) your indexPath.row * 1.0 to Double.The below code works fine.
var theDelay: NSTimeInterval = 1.0
or
var theDelay: Double = 1.0 //this is same as above
UIView.animateWithDuration( theDelay, animations: {
cell.frame.origin.y = 0
})
Compiler is misguiding you.So always pass parmeter type same as defined in Swift
Related
I'm using UIViewPropertyAnimator to control the progress of multiple animations. I have a 2d array of UIView subclasses. I want to display all elements at each index at once. For some reason the compiler won't let me add new animations with a delay by using addAnimations(_:delayFactor:) method. Can someone tell me what am I doing wrong here?
// I'm creating a new viewAnimator without any animations. No problems here
self.viewAnimator = UIViewPropertyAnimator(duration: self.frameDelay * Double(self.spillBubbles.count),
curve: .easeIn,
animations: {})
for (index, views) in self.spillBubbles.enumerated() {
views.forEach({ self.simulationView.addSubview($0) })
// That's where the compiler error occurs
self.viewAnimator!.addAnimations({
views.forEach({ self.simulationView.addSubview($0) })
}, delayFactor: Double(index) / Double(self.spillBubbles.count))
}
When I try to call .addAnimations I get the following message:
Cannot invoke 'addAnimations' with an argument list of type '(() -> (), delayFactor: Double)'
What am I doing wrong here? The same closure called in the UIViewPropertyAnimator initializers works without any issues.
The error message is pretty clear. Just look at the docs if it isn't clear enough:
https://developer.apple.com/documentation/uikit/uiviewpropertyanimator/1648370-addanimations
The delayFactor needs to be a CGFloat, not a Double.
I'm trying to create a var without assigning a value when it's initialized. I'm new to swift, coming from Objective-c, and I'm having trouble using the wrapper/unwrapper. I have the following in my code:
var elapsedTime : NSTimeInterval!
self.elapsedTime -= (NSTimeInterval(hours) * 3600)
I get the following error at the second line:
Binary operator '-=' cannot be applied to operands of type
'NSTimeInterval!' and '(Double)'
What should I do to fix that, and why am I getting an error?
It's a behavior specific to the implicitly unwrapped optional. The ! after the name of the type makes it an implictly unwrapped optional, for instance with NSTimeInterval!. The compiler will let you try and access the value inside the optional without checking for nil. If there is a nil there at runtime, your program will explode.
For some reason, -= can't be applied with the implicitly unwrapped optional on the left. NSTimeInterval is a typealias for Double, so I'm going to use a simple example.
var time = 0.0
var dangerousTime: Double! = 15.0
time -= dangerousTime // works fine
dangerousTime = dangerousTime - time // works fine
dangerousTime -= time // errors out
Implicitly unwrapped optionals are dangerous and you should avoid using them. This will probably fix your problem anyway. A few possible ways to go from here:
In Swift, you don't need an Optional to declare a variable without initialization. The compiler just won't let you use it until you've assigned it an initial value.
var time: Double
var foo = time + 5 // error
time = 4.0
foo = time + 5 // success
What you may want is a regular old Optional and a safe syntax for using the Optional.
var maybeTime: Double?
if let time = maybeTime {
maybeTime = time - 42
}
You may have run into a compiler bug.
elapsedTime is declared as an Optional, which means that it may have a value, like zero, or it may have no value.
The -= operator only has meaning when elapsedTime has a value.
If you want to handle the case where elapsedTime has no value, you can do something like this:
if let elapsedTime = self.elapsedTime {
self.elapsedTime = elapsedTime - (NSTimeInterval(hours) * 3600)
}
else {
// self.elapsedTime has no value. What do you want to do?
}
If you just want to assume that self.elapsedTime always has a value, you can do this:
let elapsedTime : NSTimeInterval = self.elapsedTime
self.elapsedTime = elapsedTime - (NSTimeInterval(hours) * 3600)
That will compile, but it will crash at runtime if self.elapsedTime has no value.
It might be a compiler bug because -= should perhaps be equivalent to the last example, but instead produces a compiler error.
I haven't used Swift that much but coming from Objective C, there's a few things about Swift that's a PITA to get my head around.
In iOS programming, we have animateWithDuration: method, which is part of UIView.
So I tried to use Xcode's autocomplete and begin to type:
UIView.animateWith
The autocomplete shows:
UIView.animateWithDuration(duration: NSTimeInterval, animations: () -> Void)
I then tabbed across to the "duration" field, and then typed in a number:
UIView.animateWithDuration(0.5, animations: () -> Void)
Then I tabbed across again to the animation block, and pressed enter like how I normally do it in Objective C, Xcode now shows:
UIView.animateWithDuration(0.5, animations: { () -> Void in
code
})
So then I tabbed one last time to replace "code" with my code:
UIView.animateWithDuration(0.5, animations: { () -> Void in
self.customView?.transform = CGAffineTransformMakeTranslation(0.0, 0.0);
})
That's when Xcode then gives me the error:
Cannot invoke 'animateWithDuration' with an argument list of type
'(FloatLiteralConvertible, animations: () -> Void)'
I don't understand. That's the autocomplete code that Xcode generated for me, why is it giving me an error ?
I noticed if do a simple statement like:
UIView.animateWithDuration(0.5, animations: { () -> Void in
var num = 1 + 1;
})
It doesn't give me any errors.
Any ideas anyone?
From "Calling Methods Through Optional Chaining":
Any attempt to set a property through optional chaining returns a
value of type Void?, which enables you to compare against nil to see
if the property was set successfully ...
Therefore the type of the expression
self.customView?.transform = CGAffineTransformMakeTranslation(0.0, 0.0)
is Void? (optional Void). And if a closure consists only of a single expression,
then this expression is automatically taken as the return value.
The error message is quite misleading, but it comes from the fact that Void? is
different from Void.
Adding an explicit return statement solves the problem:
UIView.animateWithDuration(0.5, animations: { () -> Void in
self.customView?.transform = CGAffineTransformMakeTranslation(0.0, 0.0)
return
})
Update: Adding an explicit return statement it not necessary
anymore with Swift 1.2 (Xcode 6.3). From the beta release notes:
Unannotated single-expression closures with non-Void return types can now be used in Void contexts.
In objective-C my animation bit would look something like this:
[UIView animateWithDuration:0.5 animations:^{
[[[_storedCells lastObject] topLayerView] setFrame:CGRectMake(0, 0, swipeableCell.bounds.size.width, swipeableCell.bounds.size.height)];
} completion:^(BOOL finished) {
[_storedCells removeLastObject];
}];
If I translate that into Swift it should look something like this:
UIView.animateWithDuration(0.5, animations: {
self.storedCells[1].topLayerView.frame = CGRectMake(0, 0, cell.bounds.size.width, cell.bounds.size.height)
}, completion: { (finished: Bool) in
//self.storedCells.removeAtIndex(1)
})
It complains on the commented-out line. The error I receive is: Could not find an overload for 'animateWithDuration' that accepts the supplied arguments
I know the completion closure takes a boolean value and returns a void, but I should be able to write something that is not bool related there anyway....right?
Any help is appreciated.
Edit: Here is how I declare the array I'm using in the function:
var storedCells = SwipeableCell[]()
An array that takes SwipeableCell objects.
This is a good one, tricky!
The issue is in your completion block...
A. I would begin by rewriting it like this: (not the final answer, but on our way there!)
{ _ in self.storedCells.removeAtIndex(1) }
(the _ in place of the "finished" Bool, to indicate to the reader that its value isn't being used in the block - you may also consider adding a capture list as necessary to prevent a strong reference cycle)
B. The closure you have written has a return type when it shouldn't! All thanks to Swift's handy feature "implicit returns from single expression closures" - you are returning the result of that expression, which is the element at the given index
(the type of the closure argument for completion should be ((Bool) -> Void))
This can be resolved as so:
{ _ in self.storedCells.removeAtIndex(1); return () }
I have the following function defined in a .swift file in a new project I'm creating:
func createCircle(xPos: Int, yPos: Int) {
// do code here
}
For some reason when I try to call it using the following code xcode displays an error stating "Missing argument label 'yPos:' in call".
createCircle(100, 100)
The odd thing is it treats yPos different than xPos - if I include xPos: in the calling function it highlights the line and says "Cannot convert the expression's type '$Tf' to type 'IntegerLiteralConvertable'". So the following is what I end up with in order to call the aforementioned function:
createCircle(100, yPos: 100)
Am I missing something obvious or is this an xcode beta bug?
According to the Swift documentation
Section - Methods - Local and External Parameter Names for Methods
"Specifically, Swift gives the first parameter name in a method a
local parameter name by default, and gives the second and subsequent
parameter names both local and external parameter names by default."
Judging from your error, it seems like you're using a method and not a function. You don't need to provide the name for the first parameter but you must for subsequent parameters but this behaviour can be changed with the _ (underscore character).
class MyCircle {
var xPos: Double = 0.0;
var yPos: Double = 0.0;
func createCircle(x: Double, _ y: Double) {
// insert create circle logic here.
}
}
var cir = MyCircle();
cir.createCircle(100, 100);
By using the underscore for subsequent parameters you don't have to provide the label for them when calling the method.