asyncAfter not delaying the first execution by specified time
I'm trying to animate a textview to get the string characters to appear one by one, then also disappear one by one starting with the first character after a 0.5 second delay.
I am close, the only issue I have is that the very first character gets removed immediately so it's as if it never appeared. Any ideas, here's my function:
extension UITextView {
func animate(newText: String) {
DispatchQueue.main.async {
self.text = ""
for (index, character) in newText.enumerated() {
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1 * Double(index)) {
self.text?.append(character)
}
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5 * Double(index)) {
self.text?.remove(at: newText.startIndex)
}
}
}
}
}
ios swift animation uitextview grand-central-dispatch
add a comment |
I'm trying to animate a textview to get the string characters to appear one by one, then also disappear one by one starting with the first character after a 0.5 second delay.
I am close, the only issue I have is that the very first character gets removed immediately so it's as if it never appeared. Any ideas, here's my function:
extension UITextView {
func animate(newText: String) {
DispatchQueue.main.async {
self.text = ""
for (index, character) in newText.enumerated() {
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1 * Double(index)) {
self.text?.append(character)
}
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5 * Double(index)) {
self.text?.remove(at: newText.startIndex)
}
}
}
}
}
ios swift animation uitextview grand-central-dispatch
2
By the way, ifnewText
is especially long, you'll find that the first characters will start out evenly, but latter characters will start coming out in spurts. This is "timer coalescing", where distantly scheduled blocks are queued up at the same time to reduce battery drain. You may want to use a different pattern (e.g. a single repeating timer).
– Rob
Dec 31 '18 at 0:35
1
Do you really mean to add characters every 0.1 seconds and remove them every 0.5 seconds? E.g. after 10 seconds, 100 characters could be added but only 20 of them removed (assuming your string was that long). Is that really the UX you're going for? Or did you mean to add a character every 0.1 seconds and have each character removed 0.5 seconds after it was added (which is not what the above will do).
– Rob
Dec 31 '18 at 0:45
thanks @Rob, this is a good point that I had not considered, I'll probably need to go with a timer to avoid the timer coalescing. I'm still working on the timing of the animation, I do want some sort of an offset, not a direct 1:1. Thanks for the help, much appreciated
– TJMac
Dec 31 '18 at 1:28
add a comment |
I'm trying to animate a textview to get the string characters to appear one by one, then also disappear one by one starting with the first character after a 0.5 second delay.
I am close, the only issue I have is that the very first character gets removed immediately so it's as if it never appeared. Any ideas, here's my function:
extension UITextView {
func animate(newText: String) {
DispatchQueue.main.async {
self.text = ""
for (index, character) in newText.enumerated() {
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1 * Double(index)) {
self.text?.append(character)
}
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5 * Double(index)) {
self.text?.remove(at: newText.startIndex)
}
}
}
}
}
ios swift animation uitextview grand-central-dispatch
I'm trying to animate a textview to get the string characters to appear one by one, then also disappear one by one starting with the first character after a 0.5 second delay.
I am close, the only issue I have is that the very first character gets removed immediately so it's as if it never appeared. Any ideas, here's my function:
extension UITextView {
func animate(newText: String) {
DispatchQueue.main.async {
self.text = ""
for (index, character) in newText.enumerated() {
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1 * Double(index)) {
self.text?.append(character)
}
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5 * Double(index)) {
self.text?.remove(at: newText.startIndex)
}
}
}
}
}
ios swift animation uitextview grand-central-dispatch
ios swift animation uitextview grand-central-dispatch
edited Dec 31 '18 at 1:16
Rob
299k49557726
299k49557726
asked Dec 30 '18 at 23:53
TJMacTJMac
266
266
2
By the way, ifnewText
is especially long, you'll find that the first characters will start out evenly, but latter characters will start coming out in spurts. This is "timer coalescing", where distantly scheduled blocks are queued up at the same time to reduce battery drain. You may want to use a different pattern (e.g. a single repeating timer).
– Rob
Dec 31 '18 at 0:35
1
Do you really mean to add characters every 0.1 seconds and remove them every 0.5 seconds? E.g. after 10 seconds, 100 characters could be added but only 20 of them removed (assuming your string was that long). Is that really the UX you're going for? Or did you mean to add a character every 0.1 seconds and have each character removed 0.5 seconds after it was added (which is not what the above will do).
– Rob
Dec 31 '18 at 0:45
thanks @Rob, this is a good point that I had not considered, I'll probably need to go with a timer to avoid the timer coalescing. I'm still working on the timing of the animation, I do want some sort of an offset, not a direct 1:1. Thanks for the help, much appreciated
– TJMac
Dec 31 '18 at 1:28
add a comment |
2
By the way, ifnewText
is especially long, you'll find that the first characters will start out evenly, but latter characters will start coming out in spurts. This is "timer coalescing", where distantly scheduled blocks are queued up at the same time to reduce battery drain. You may want to use a different pattern (e.g. a single repeating timer).
– Rob
Dec 31 '18 at 0:35
1
Do you really mean to add characters every 0.1 seconds and remove them every 0.5 seconds? E.g. after 10 seconds, 100 characters could be added but only 20 of them removed (assuming your string was that long). Is that really the UX you're going for? Or did you mean to add a character every 0.1 seconds and have each character removed 0.5 seconds after it was added (which is not what the above will do).
– Rob
Dec 31 '18 at 0:45
thanks @Rob, this is a good point that I had not considered, I'll probably need to go with a timer to avoid the timer coalescing. I'm still working on the timing of the animation, I do want some sort of an offset, not a direct 1:1. Thanks for the help, much appreciated
– TJMac
Dec 31 '18 at 1:28
2
2
By the way, if
newText
is especially long, you'll find that the first characters will start out evenly, but latter characters will start coming out in spurts. This is "timer coalescing", where distantly scheduled blocks are queued up at the same time to reduce battery drain. You may want to use a different pattern (e.g. a single repeating timer).– Rob
Dec 31 '18 at 0:35
By the way, if
newText
is especially long, you'll find that the first characters will start out evenly, but latter characters will start coming out in spurts. This is "timer coalescing", where distantly scheduled blocks are queued up at the same time to reduce battery drain. You may want to use a different pattern (e.g. a single repeating timer).– Rob
Dec 31 '18 at 0:35
1
1
Do you really mean to add characters every 0.1 seconds and remove them every 0.5 seconds? E.g. after 10 seconds, 100 characters could be added but only 20 of them removed (assuming your string was that long). Is that really the UX you're going for? Or did you mean to add a character every 0.1 seconds and have each character removed 0.5 seconds after it was added (which is not what the above will do).
– Rob
Dec 31 '18 at 0:45
Do you really mean to add characters every 0.1 seconds and remove them every 0.5 seconds? E.g. after 10 seconds, 100 characters could be added but only 20 of them removed (assuming your string was that long). Is that really the UX you're going for? Or did you mean to add a character every 0.1 seconds and have each character removed 0.5 seconds after it was added (which is not what the above will do).
– Rob
Dec 31 '18 at 0:45
thanks @Rob, this is a good point that I had not considered, I'll probably need to go with a timer to avoid the timer coalescing. I'm still working on the timing of the animation, I do want some sort of an offset, not a direct 1:1. Thanks for the help, much appreciated
– TJMac
Dec 31 '18 at 1:28
thanks @Rob, this is a good point that I had not considered, I'll probably need to go with a timer to avoid the timer coalescing. I'm still working on the timing of the animation, I do want some sort of an offset, not a direct 1:1. Thanks for the help, much appreciated
– TJMac
Dec 31 '18 at 1:28
add a comment |
1 Answer
1
active
oldest
votes
The problem is that the first character has an index of 0
, so the delay is .now() + 0.5 * 0
, which simplifies to just .now()
.
Add a constant to the delay:
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5 * Double(index) + 0.5) {
^^^^^^
This will cause the first character to disappear 1 second later.
Alternatively:
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5 * Double(index + 1)) {
In addition, using a Timer
here can be more suitable if your text is long, as Rob has said n the comments.
var index = 0
let characterArray = Array(newText)
Timer.scheduledTimer(withTimeInterval: 0.1, repeats: true) { (timer) in
textView.text! += "(characterArray[index])"
index += 1
if index == characterArray.endIndex {
timer.invalidate()
}
}
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53982398%2fasyncafter-not-delaying-the-first-execution-by-specified-time%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
The problem is that the first character has an index of 0
, so the delay is .now() + 0.5 * 0
, which simplifies to just .now()
.
Add a constant to the delay:
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5 * Double(index) + 0.5) {
^^^^^^
This will cause the first character to disappear 1 second later.
Alternatively:
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5 * Double(index + 1)) {
In addition, using a Timer
here can be more suitable if your text is long, as Rob has said n the comments.
var index = 0
let characterArray = Array(newText)
Timer.scheduledTimer(withTimeInterval: 0.1, repeats: true) { (timer) in
textView.text! += "(characterArray[index])"
index += 1
if index == characterArray.endIndex {
timer.invalidate()
}
}
add a comment |
The problem is that the first character has an index of 0
, so the delay is .now() + 0.5 * 0
, which simplifies to just .now()
.
Add a constant to the delay:
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5 * Double(index) + 0.5) {
^^^^^^
This will cause the first character to disappear 1 second later.
Alternatively:
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5 * Double(index + 1)) {
In addition, using a Timer
here can be more suitable if your text is long, as Rob has said n the comments.
var index = 0
let characterArray = Array(newText)
Timer.scheduledTimer(withTimeInterval: 0.1, repeats: true) { (timer) in
textView.text! += "(characterArray[index])"
index += 1
if index == characterArray.endIndex {
timer.invalidate()
}
}
add a comment |
The problem is that the first character has an index of 0
, so the delay is .now() + 0.5 * 0
, which simplifies to just .now()
.
Add a constant to the delay:
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5 * Double(index) + 0.5) {
^^^^^^
This will cause the first character to disappear 1 second later.
Alternatively:
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5 * Double(index + 1)) {
In addition, using a Timer
here can be more suitable if your text is long, as Rob has said n the comments.
var index = 0
let characterArray = Array(newText)
Timer.scheduledTimer(withTimeInterval: 0.1, repeats: true) { (timer) in
textView.text! += "(characterArray[index])"
index += 1
if index == characterArray.endIndex {
timer.invalidate()
}
}
The problem is that the first character has an index of 0
, so the delay is .now() + 0.5 * 0
, which simplifies to just .now()
.
Add a constant to the delay:
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5 * Double(index) + 0.5) {
^^^^^^
This will cause the first character to disappear 1 second later.
Alternatively:
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5 * Double(index + 1)) {
In addition, using a Timer
here can be more suitable if your text is long, as Rob has said n the comments.
var index = 0
let characterArray = Array(newText)
Timer.scheduledTimer(withTimeInterval: 0.1, repeats: true) { (timer) in
textView.text! += "(characterArray[index])"
index += 1
if index == characterArray.endIndex {
timer.invalidate()
}
}
edited Dec 31 '18 at 0:52
answered Dec 31 '18 at 0:11
SweeperSweeper
66.7k1073139
66.7k1073139
add a comment |
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53982398%2fasyncafter-not-delaying-the-first-execution-by-specified-time%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
2
By the way, if
newText
is especially long, you'll find that the first characters will start out evenly, but latter characters will start coming out in spurts. This is "timer coalescing", where distantly scheduled blocks are queued up at the same time to reduce battery drain. You may want to use a different pattern (e.g. a single repeating timer).– Rob
Dec 31 '18 at 0:35
1
Do you really mean to add characters every 0.1 seconds and remove them every 0.5 seconds? E.g. after 10 seconds, 100 characters could be added but only 20 of them removed (assuming your string was that long). Is that really the UX you're going for? Or did you mean to add a character every 0.1 seconds and have each character removed 0.5 seconds after it was added (which is not what the above will do).
– Rob
Dec 31 '18 at 0:45
thanks @Rob, this is a good point that I had not considered, I'll probably need to go with a timer to avoid the timer coalescing. I'm still working on the timing of the animation, I do want some sort of an offset, not a direct 1:1. Thanks for the help, much appreciated
– TJMac
Dec 31 '18 at 1:28