WWDC22 SALE: Save 50% on all my Swift books and bundles! >>

SOLVED: Improve memory performance

Forums > Swift

Currently I have a log of activities that are simply concatinated to a string within a a scrollable TextView. As the log grows, this becomes very clumsy as the whole string gets recreated with each new line.

If I changed this to an array of lines, does array append require the whole array to be regenerated or does it just use (effectively) pointers?

The log can become very long, 1,000s of lines.

PS - similarily, in an editor, is the use of a string favoured over the use of an array of strings? An array of strings would be the normal case in C.

   

Using Playground on a M1 iPad Pro I ran a test with 10 million string additions.

In one test, I concatinated 10 million strings together, adding the latest to the already collected string.

In the other test, I added a new string as a new row in an array of strings.

Both were very fast with the array test being generally 13% faster than the concatination.

In further reading, it appears that Swift uses a "write on change" approach with strings and arrays. Since my tests didn't access the string collection nor elements, I think my tests are flawed. That is to say, Swift took a short cut to process the loops that wouldn't be the case if I was displaying the string or array in a scrollable Text View.

Does any of this make sense?

1      

Brilliant analysis!

What on earth are you doing where you might collect 10 million (!) strings. I can't even!

Michael: "Hey M1 chip! Here are 10 million strings for you to concatenate! Ready, steady, GO!"
M1 Chip: Yawn

   

From the docs:

Because arrays increase their allocated capacity using an exponential strategy, appending a single element to an array is an O(1) operation when averaged over many calls to the append(_:) method. When an array has additional capacity and is not sharing its storage with another instance, appending an element is O(1). When an array needs to reallocate storage before appending or its storage is shared with another copy, appending is O(n), where n is the length of the array.

Complexity: O(1) on average, over many calls to append(_:) on the same array.

Does this answer your question?

1      

In further reading, it appears that Swift uses a "write on change" approach with strings and arrays.

Do you mean "copy on write"? All that means is that if you have, say an array of 10 million Strings and create a copy of it, behind the scenes Swift doesn't actually make a copy until/unless you change something in the copy. Otherwise it just stores a reference to the original storage.

So...

let a1 = [...10 million Strings...]  //big-ass array allocated
var a2 = a1 //no allocation here
a2.append("one more string") //NOW we allocate a new array and append the additional String

1      

Hacking with Swift is sponsored by Emerge

SPONSORED Why are Swift reference types bad for app startup time, and what’s the performance cost of protocol conformances? That’s just a couple of the topics you can learn about on the Emerge blog — written by the app performance experts behind Emerge’s advanced app optimization and monitoring tools, based on their experience of working at companies like Apple, Airbnb, Snap, and Spotify.

Find out more

Sponsor Hacking with Swift and reach the world's largest Swift community!

Reply to this topic…

You need to create an account or log in to reply.

All interactions here are governed by our code of conduct.

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.