I am new to programming and am trying to learn Swift and Xcode with the help of the book "Swift for Beginners: Develop and Design". The book has been helpful so far and I have learned a lot already, however, it seems that Swift and Xcode have been updated since the book came out and that has led to some changes.
I am currently trying to code the sample memory game in Chapter 9, and I've run into a problem. Up until now, any differences caused by an updated version of Swift I have been able to figure out on my own, but this one is stumping me.
The code causing the error is this:
UIView.animateWithDuration(highlightTime,
delay: 0.0,
options: [.CurveLinear, .AllowUserInteraction, .BeginFromCurrentState],
animations: {
button.backgroundColor = highlightColor
}, completion: { finished in
button.backgroundColor = originalColor
var newIndex : Int = index + 1
self.playSequence(newIndex, highlightTime: highlightTime)
})
The error message is this:
Cannot invoke 'animateWithDuration' with an argument list of type '(Double, delay: Double, options: UIViewAnimationOptions, UIViewAnimationOptions, UIViewAnimationOptions, animations: () -> (), completion: (_) -> _)'
And the suggestion is this:
Expected an argument list of type '(NSTimeInterval, delay: NSTimeInterval, options: UIViewAnimationOptions, animations: () -> Void, completion: ((Bool) -> Void)?)'
Any help or insight would be appreciated.
Swift is picky with casting, so wrap the numbers in NSTimeInterval
UIView.animateWithDuration(NSTimeInterval(highlightTime),
delay: NSTimeInterval(0.0),
options: [.CurveLinear, .AllowUserInteraction, .BeginFromCurrentState],
animations: {
button.backgroundColor = highlightColor
}, completion: { finished in
button.backgroundColor = originalColor
var newIndex : Int = index + 1
self.playSequence(newIndex, highlightTime: highlightTime)
})
It seems like your highlightTime is defined as some other type not as Double, while defining the variable, simply define its type as,
let highlightTime: Double = 1.0
And, that should fix it.
Thanks for the feedback, everyone.
After some time, I was able to figure it out.
I had previously declared the highlightTime variable as "highlightTime: Double", with no value assigned. I changed it to "highlightTime: NSTimeInterval" and it is working now.
Related
I'm a noob and have been learning from Apple's Playgrounds and random books doing tutorials. I'm working on a tutorial where it deals with a closure. I've seen this 'finish in' before in another tutorial but I don't know what it means precisely in layman terms.
What is it finishing, what is being finished, and inside of what? Or is there an idea of order of operation?
Here is the function where it was used:
func playSequence(index: Int, highlightTime: Double){
currentPlayer = .Computer
if index == inputs.count{
currentPlayer = .Human
return
}
var button: UIButton = buttonByColor(color: inputs[index])
var originalColor: UIColor? = button.backgroundColor
var highlightColor: UIColor = UIColor.white
UIView.animate(withDuration: highlightTime, delay: 0.0, options: [.curveLinear, .allowUserInteraction, .beginFromCurrentState], animations: {
button.backgroundColor = highlightColor
}, completion: {
finished in button.backgroundColor = originalColor
var newIndex: Int = index + 1
self.playSequence(index: newIndex, highlightTime: highlightTime)
})
}
finished is the parameter to the completion closure. The in is simply part of Swift's closure syntax.
The full signature of the UIView animate method is:
class func animate(withDuration duration: TimeInterval, delay: TimeInterval, options: UIViewAnimationOptions = [], animations: #escaping () -> Void, completion: ((Bool) -> Void)? = nil)
Note the Bool parameter to the completion closure. The finished in your code is the name given to that parameter.
An excerpt from the documentation about the completion parameter states:
This block has no return value and takes a single Boolean argument that indicates whether or not the animations actually finished before the completion handler was called.
A more typical way to write the code is as:
UIView.animate(withDuration: highlightTime, delay: 0.0, options: [.curveLinear, .allowUserInteraction, .beginFromCurrentState], animations: {
// animation code
}) { (finished) in
// completion code
}
This syntax makes it clearer than the syntax you are using. This is also using the "trailing closure" syntax.
Another way, closer to your usage, would be:
UIView.animate(withDuration: highlightTime, delay: 0.0, options: [.curveLinear, .allowUserInteraction, .beginFromCurrentState], animations: {
// animation code
}, completion: { (finished) in
// completion code
})
Your usage simply omits the parentheses around the parameter and it leaves out a line break. Adding those back in makes the code clearer.
I can't figure out the proper syntax for calling the UIView method animateWithDuration. I've found some examples where others have had similar problems, and the solutions for those don't seem to work in the most recent version of Swift, 2.0. I'm getting this generic error:
Cannot invoke 'animateWithDuration' with an argument list of type '(duration: Double, delay: Double, options: UIViewAnimationTransition, animations: ()->_, completion: nil)'
I believe I've narrowed the problem down to the "animations:" parameter. Here is my code:
UIView.animateWithDuration(duration: 0.2,
delay: 0.0,
options: UIViewAnimationTransition.FlipFromLeft,
animations: {
// Hide image here
},
completion: nil)
Any suggestions would be appreciated, thanks.
Try this:
UIView.animateWithDuration(0.2, delay: 0, options: UIViewAnimationOptions.CurveEaseInOut, animations: { () -> Void in
}, completion: nil)
Xcode code completion usually helps figure these things out. :-)
Also, for the animation options you're using a constant meant for something else. Use UIViewAnimationOptions instead.
Get rid of the duration label on the first parameter:
UIView.animateWithDuration(0.2,
delay: 0.0,
options: UIViewAnimationTransition.FlipFromLeft,
animations: {
// Hide image here
},
completion: nil)
Before explain my problem, it is important to say that I already implemented the suggestion made in this question and I think my doubts about this animateWithDuration method are quite different, despite both questions having a very similar title.
So, I am a Swift newbie and I am doing some small projects in Swift, based on previous Objective C demos that I did before.
This is my Objective C code:
- (void)moveSideBarToXposition: (int) iXposition{
[UIView animateWithDuration:0.5f
delay:0.1
options: UIViewAnimationOptionTransitionNone
animations:^{ self.mainView.frame = CGRectMake(iXposition, 20, self.mainView.frame.size.width, self.mainView.frame.size.height); }
completion:^(BOOL finished){
if (self.isSidebarHidden==YES) {
self.isSidebarHidden = NO;
}
else{
self.isSidebarHidden = YES;
}
}];
}
And this is my Swift version:
func moveSideBarToXposition(iXposition: Float) {
UIView.animateWithDuration(0.5, delay: 1.0, options: UIViewAnimationTransition.None, animations: { () -> Void in
self.contentView.frame = CGRectMake(iXposition, 20, self.contentView.frame.size.width, self.contentView.frame.size.height)
}, completion: { (finished: Bool) -> Void in
if isMenuHidden == true {
isMenuHidden = false
} else {
isMenuHidden = true
}
})
}
And I get this error.
Cannot invoke 'animateWithDuration' with an argument list of type
'(Double, delay: Double, options: UIViewAnimationTransition,
animations: () -> Void, completion: (Bool) -> Void)'
I read the documentation but actually I am not sure what the problem is.
Btw, i am working on Xcode 7 and Swift 2.0
You are passing enum of type UIViewAnimationTransition to an argument which requires type UIViewAnimationOptions (options argument)
Here is the correct syntax with the correct enum value:
func moveSideBarToXposition(iXposition: Float) {
let convertedXposition = CGFloat(iXposition)
UIView.animateWithDuration(0.5, delay: 1.0, options: UIViewAnimationOptions.TransitionNone, animations: { () -> Void in
self.contentView.frame = CGRectMake(convertedXposition, 20, self.contentView.frame.size.width, self.contentView.frame.size.height)
}, completion: { (finished: Bool) -> Void in
// you can do this in a shorter, more concise way by setting the value to its opposite, NOT value
isMenuHidden = !isMenuHidden
})
}
I am trying to use JSSAlertView (github.com/stakes/JSSAlertView) with Swift 2.0 but I have an error :
Cannot invoke animateWithDuration with an argument list of type '(Double, delay: Double, usingSpringWithDampling: Double, initialSpringVelocity: Double, options: nil, animations () -> _, completion: (Bool) -> _)'
for the code :
UIView.animateWithDuration(0.5, delay: 0.05, usingSpringWithDamping: 0.8, initialSpringVelocity: 0.5, options: nil, animations: {
self.containerView.center = self.rootViewController.view.center
}, completion: { (finished: Bool) in
})
I saw this two answers :
Nested closures does not like argument list
UIView Animation in Swift not working, wrong arguments error
but they don't help me.
I still think that the problem comes either from the "animations" or the "completion".
Starting in Swift 2, option sets are not nil-convertible anymore, so you can't use nil. However, they are array literal convertible (for an array of options to be OR'd together), so you can use [] for no options.
You have to provide a different options than nil. For example .CurveEaseInOut:
UIView.animateWithDuration(0.5, delay: 0.05, usingSpringWithDamping: 0.8, initialSpringVelocity: 0.5, options: .CurveEaseInOut, animations: {
self.containerView.center = self.rootViewController.view.center
}, completion: { (finished: Bool) in
})
I am trying to use animateWithDuration closure in Swift. I have declared the arguments in the closure as mentioned in the Apple Book for Swift. However, I am still getting an error.
Below is the code snippet:
if(!isRotating){
isRotating = true
var myImageTemp :UIImageView = self.myImage
UIView.animateWithDuration(0.5, delay: 1, options: UIViewAnimationCurve.EaseOut, animations:
{
() in myImageTemp.transform = CGAffineTransformMakeRotation(angle + M_PI_2)
},
completion:
{
(Bool finished) in self.pathAnimation() })
}
It gives me an error:
Could find an overload that accepts the supplied arguments.
And also it tells me:
Implicit use of self in closure.
Can anybody help me with this?
Just try:
UIView.animateWithDuration(0.2,
animations:
{
// your code.
},
completion:
{
(completed: Bool) in
// your code.
})
The (completed: Bool) in part indicates that the closure takes a Bool parameter labeled completed. If you are not interested in accessing the completed parameter, you can ignore it using an underscore.
UIView.animateWithDuration(0.2,
animations:
{
// your code.
},
completion:
{ _ in
// your code.
})