I need to find out the size of an array (Swift 4 AnyObject) I just downloaded. Every mobile device has some free memory (size varies per user) and I need a way to examine the size of my download. I have searched and can't find a reasonable answer. Hope you can help!
This seems to be impossible currently. But if you just need a rough estimate, you can use class_getInstanceSize:
func size<T: AnyObject>(_ array: [T]) -> Int {
return class_getInstanceSize(T.self) * array.count
}
For this example array
class Test {
var a: Bool = false
var b: Int = 0
var c: String = ""
}
let array = [Test(), Test(), Test()]
you will get a size of 168. See this post for more information.
Of course, this approach will not work well with fields of variable length, for example with strings or arrays. The only possibility I see to get an accurate value is to write a function for each possible class to calculate the exact number of bytes need. For a string, for example, you can calculate the number of bytes with
"test".data(using: .utf8)!.count
But even with this approach you will not get the real size of the memory Swift uses internally to store the array.
So the question is: Why do you need to know the size of the array? And what is the reason that you do not know the size of downloaded data? If those data are received from outside, they must already be encoded in a byte representation, so counting should be quite easy.
Related
And why?
Given the following Swift code:
struct DemoStruct {
let buf: [UInt8]
init?(fromArray buf: [UInt8]) {
guard buf.count == 6 else {
return nil
}
self.buf = buf
}
var containsJustZeros: Bool {
// test code
}
}
let data = DemoStruct(fromArray: Array(repeating: 0, count: 6))!
if data.containsJustZeros {
print("zeros")
}
For the test code part I've implemented and measured the following implementations:
self.buf == Array(repeating: 0, count: 6)
for dig in self.buf where dig != 0 { return false } return true
self.buf.elementsEqual(Array(repeating: 0, count: 6))
Whereas the first code is the fastest (~13 sec/10 000 000 tests) and the last one the slowest (~43 sec/10 000 000 tests). Is there any other implementation possible? I would like to optimise my code for speed and understand Swift much better.
First of all: this Data struct is a really bad idea, that's pretty much certain to lead to confusion. Foundation already has a struct called Data, and it's totally ubiquitous, because it's the "common currency" type for shuttling around untyped bytes of miscellaneous data.
Furthermore, you don't really get anyhting from using [UInt8]. Just use Foundation.Data.
As for your main question.
The first technique allocates an array, and uses == to compare it. There's absolutely no reason to allocate 6 zeros. If buf had a billiion elements, would you allocate a billion elements? Wasteful.
The second technique is better, because you're not allocating in unnecessary element, just for the sake of comparison. However, it's hand-rolling a feature that already exists in the standard library (allSatisfy(_:), which I'll get into later.)
elementsEqual is a more generic version of ==, which can compare one sequence to any other sequence. You chose to compare it to an array of 6 zeros, but that's bad (for the same reason as 0). Instead, you could use repeatElement(0, count: 6) to produce an element that doesn't actually need to store n copies. It stores just one, and wraps it in a way that conforms to the Collection protocol.
The best approach of all, is to just use allSatisfy. It's fast, it doesn't allocate anything unnecessary, and most importantly it's descriptive of exactly what you're trying to express:
var containsJustZeros: Bool {
self.buf.allSatisfy { byte in byte == 0 }
}
However, I wouldn't implement this in computed property. Those have a conventional expectation of being fast, whereas this is doing a linear scan through the entire buffer. Unless you want to cache the result in a stored boolean property, I would change this to a func.
I noticed that this:
let a = [Float](repeating: 0, count: len)
takes very significantly more time than just
let p = UnsafeMutablePointer<Float>.allocate(capacity: len)
However, the unsafe pointer is not so convenient to use, and one may want to create a Array<Float> to pass onto other code.
let a = Array(UnsafeBufferPointer(start: p, count: len))
But doing this absolutely kills it, and it is faster to just create the Array with zeros filled in.
Any idea how to create an Array faster and at the same time, have an actual Array<Float> handy? In the context of my project, I can probably deal with the unsafe pointer internally and wrap it with Array only when needed outside the module.
Quick test on all the answers in this post:
let len = 10_000_000
benchmark(title: "array.create", num_trials: 10) {
let a = [Float](repeating: 0, count: len)
}
benchmark(title: "array.create faster", num_trials: 10) {
let p = UnsafeMutableBufferPointer<Float>.allocate(capacity: len)
}
benchmark(title: "Array.reserveCapacity ?", num_trials: 10) {
var a = [Float]()
a.reserveCapacity(len)
}
benchmark(title: "ContiguousArray ?", num_trials: 10) {
let a = ContiguousArray<Float>(repeating: 0, count: len)
}
benchmark(title: "ContiguousArray.reserveCapacity", num_trials: 10) {
var a = ContiguousArray<Float>()
a.reserveCapacity(len)
}
benchmark(title: "UnsafeMutableBufferPointer BaseMath", num_trials: 10) {
let p = UnsafeMutableBufferPointer<Float>(len) // Jeremy's BaseMath
print(p.count)
}
Results: (on 10 million floats)
array.create: 9.256 ms
array.create faster: 0.004 ms
Array.reserveCapacity ?: 0.264 ms
ContiguousArray ?: 10.154 ms
ContiguousArray.reserveCapacity: 3.251 ms
UnsafeMutableBufferPointer BaseMath: 0.049 ms
I am doing this adhocly running an app on iphone simulator in Release mode. I know i should probably do this in commandline/standalone, but since i plan to write this as part of an app, this may be alright.
For what I tried to do, UnsafeMutableBufferPointer seemed great, but you have to use BaseMath and all its conformances. If you are after a more general or other context. Be sure to read everything and decide which one works for you.
If you need performance, and know the size you need, you can use reserveCapacity(_:), this will preallocate the memory needed for the contents of the array. Per Apple documentation:
If you are adding a known number of elements to an array, use this method to avoid multiple reallocations. This method ensures that the array has unique, mutable, contiguous storage, with space allocated for at least the requested number of elements.
Calling the reserveCapacity(_:) method on an array with bridged storage triggers a copy to contiguous storage even if the existing storage has room to store minimumCapacity elements.
For performance reasons, the size of the newly allocated storage might be greater than the requested capacity. Use the array’s capacity property to determine the size of the new storage.
This is the closest thing to what I want. There's a library called BaseMath (started by Jeremy Howard), and there's a new class call AlignedStorage and UnsafeMutableBufferPointer. It is endowed with lot of math, and pretty-to-very fast too, so this reduce lot of managing of pointers while juggling math algorithm.
But this remains to be tested, this project is very new. I will leave this Q open to see if someone can suggest something better.
Note: this is the fastest in the context of what I am doing. If you really need a good struct value type Array (and variants), see other ans.
I am currently attempting to learn how to code swift via treehouse.com and so far I am enjoying it. I just came to my first "code challenge" as they call it that I somewhat struggled on. As the title suggested, the started with an empty array as such:
var results: [Int] = []
That is fine and dandy. The goal is to then write a for in loop which finds the multiples of 6 for the numbers 1-10 and then to append those values to the array. I eventually did figure it out, but I am not sure that I did it in the ideal way. I'd appreciate any criticism. My code will be included below. Do bear in mind that I am a total beginner to Swift and to coding in general. Thanks in advance for any suggestions/tips.
var results: [Int] = []
for multiplier in 1...10 {
let multiples = (multiplier * 6)
print(multiples)
results.append(multiples)
}
The code executes properly and the array is appended with the values, but again, I am unsure if there is a better way to do this.
For your first question, Is there batter way or best way to append objects in array in for in loop is already explain by #Alexander, But if check properly he is still at last doing the same way you are doing the difference is only that he has specified the capacity of array, So the way you are appending object in array is look like perfect but for that you need to write to much code.
Now to reduce your code and do what you are currently doing in a Swifty way you can use built in map function for that.
let result = (1...10).map { $0 * 6 }
print(result) // [6, 12, 18, 24, 30, 36, 42, 48, 54, 60]
First (1...10) will create CountableClosedRange after that we are calling map(_:) closure with it. Now map will sequentially take each element from this CountableClosedRange. So $0 will take each argument from CountableClosedRange. Now we are multiplying that element with 6 and returning the result from the closure and generate the result according to its return value in this case it will create Array of Int.
This is a great question, and a perfect opportunity to explain map and array reallocation costs.
Arrays have two important properties you need to understand.
The first is their count. The count is simply the number of items in the array.
The other is the capacity. The capacity is the number of elements that can fit the memory that has been allocated for this array. The capacity is always ≥ the count (d'uh!).
When you have an Array of say, capacity 10, and count 5, and you try to append to it, you can do that right away. Set the 6th element to the new value, and boom, you're done instantly.
Now, what happens if you have an Array of capacity 10, and count 10, and you try to append to it? Well there's no more room for new elements given the memory the array currently has allocated. What needs to happen is that the Array has to ask the operating system for a new chunk of memory that has a capacity that's high enough to fit at least the existing elements, plus the new incoming element. However, this new chunk of memory is empty, so we need to copy over what we had in our old small chunk of memory, before we can do the append. Suppose our new chunk has capacity 20, and we copy our 10 old elements. We can now add in our new element in the 11th slot.
Notice we had to copy the elements from our old memory into the new memory. Well if our count is 10, that's 10 copy operations. This means that appending to an array that's at capacity is much slower than appending an array with available capacity.
Suppose we go on to add another 1000 elements.
- Our array will fill its new memory at count 20, so it'll need to reallocate a new piece of memory, do 20 copy operations. Suppose this new piece of memory has capacity 40.
- Our array will fill its new memory at count 40, so it'll need to reallocate a new piece of memory, do 40 copy operations. Suppose this new piece of memory has capacity 80.
- This process will repeat at count = 80, 160, 320, 640, until we finally have all 1011 elements in our array of capacity 1280. This took 10 + 20+ 40 + 80 + 160 + 320 + 640 = 1270 copy operations in total!
What if we were smart about this, and knew in advance that we were about to add 1000 items, and could tell the array to resize itself all at once, to fit our new 1000 items?
Well we can do exactly that, with reserveCapacity(_:). It lets us tell the array to allocate a certain capacity for us, rather than it having to constantly resize on-demand as we keep stuffing it. Using this technique, we can ensure now copy operations occur at all!
Now let's apply that to your code. We can rewrite it like so, to ensure no array reallocaitons happen (even it 1...10 were something higher, like 1...10000000)
let numbers = 1...10
let numberCount = numbers.count
var products = [Int]()
products.reserveCapacity(numberCount)
for number in numbers {
let product = (number * 6)
print(product)
products.append(product)
}
Now all that is quite a bit of code, for such a simple operation. It's also a pretty common operation. This is why map exists, to simplify all this.
map(_:) takes a closure which tells it what to do to each element. map(_:) will take every element in your sequence (in this case, your CountableClosedRange<Int>, 0...10, but it can be an Array, or any other Sequence), run it through your closure to produce some result, and put the result in the final array.
Internally, map(_:) works very similar to the code you wrote above. It creates a mutable array, reserves enough capacity for all the elements, and runs a for loop which repeatedly appends to that array. The nice thing is that it hides all this logic from you, so all you have to see is this really simple statement:
let produces = (1...10).map{ $0 * 6 }
Closures are explained simply, and in great detail in the Swift Progamming Language Guide. I suggest you take a look when you have a chance!
so I am working on a graphical calculator (bit more of a challenge than the basic windows one), and I want to be able to do the entire "math" in one textfield, just like typing in "5+3-5*11/3" and it gives you the solution when you press '='
I decided to make it with arrays of numbers and symbols, but I have no idea how to make it to fill the next array if this one already is used:
var numbers:Array = new Array("","","","","","","","","","","","","","","","");
var actions:Array = new Array("","","","","","","","","","","","","","","","");
I am using split to split the numbers I input with symbols, and I want the numbers to be placed in the arrays. Example: I type in 555+666 and then I need to have something like
if (numbers[0] = "") {numbers[0] = 555}
else if (numbers[1] = "") {numbers[1] = 555}
else if.....
Know what I mean?
Pretty hard to describe...
something like... When I type in a number, if the numbers[0] is already filled, go fill in numbers[1], if numbers[1] is filled, go to numbers[2] etc
Even if I agree with #Nbooo and the Reverse Polish Notation
However Vectors may have a fixed length.
This is not an answer but just an example (if the length of Your Array must be defined):
//Just for information..
var numbs:Vector.<Number> = new Vector.<Number>(10,true);
var count:uint = 1;
for (var i in numbs){
numbs[i] = count++
}
trace(numbs);
// If You try to add an element to a Vector,
// You will get the following Error at compile time :
/*
RangeError: Error #1126: Cannot change the length of a fixed Vector.
at Vector$double/http://adobe.com/AS3/2006/builtin::push()
at Untitled_fla::MainTimeline/frame1()
*/
numbs.push(11);
// Will throw an Error #1126
trace(numbs);
If You use this code to update a fixed Vector, this will not throw an ERROR :
numbs[4]=11;
trace(numbs);
Output :
1,2,3,4,5,6,7,8,9,10
1,2,3,4,11,6,7,8,9,10
// length is 10, so no issue...
If You consider the performance between Arrays and vectors check this reference : Vector class versus Array class
I hope this may be helpful.
[EDIT]
I suggest you to check at those links too :
ActionScript 3 fundamentals: Arrays
ActionScript 3 fundamentals: Associative arrays, maps, and dictionaries
ActionScript 3 fundamentals: Vectors and ByteArrays
[/EDIT]
Best regards.
Nicolas.
What you want to implement is the Reverse Polish Notation. In actionscript3 arrays are dynamic, not fixed size, that means you can add elements to the array without concern about capacity (at least in your case).
const array:Array = new Array();
trace(array.length); // prints 0
array.push(1);
array.push(2);
trace(array.length); // prints 2
I suggest using "push" and "pop" methods of Array/Vector, since it's much more natural for such task. Using those methods will simplify your implementation, since you'll get rid of unnecessary checks like
if (numbers[1] == "") {...}
and replace it just with:
numbers.push(value);
and then to take a value from the top:
const value:String = numbers.pop();
I need to edit the pixels' raw binary values of an image. For this, I did this steps:
I obtained the CFData containing the hex dump of the image.
I converted the CFData obtained to an array of characters (using convertToArray function)
After that, I used convertToBinaryString function to obtain a string representing the base 2 value of the hex dump.
It does work and does the job for small files but when it comes to bigger ones it takes forever to finish. I failed in the struggle of finding a faster way. Could you help me?
Down here you can take a look of the functions I need to optimize:
func convertToArray(imageData : CFData) -> Array<Character>{
let arrayData : Array<Character> = Array(String(NSData(data: imageData)).characters)
print("Array : ")
Swift.print(arrayData)
return arrayData
}
func convertToBinaryString(array : Array<Character>) -> String{
let numberOfChars = array.count
var binaryString = convertHexToBinary(array[1])
for character in 2...numberOfChars - 2{
binaryString = binaryString + convertHexToBinary(array[character])
}
// print("BINARRY ARRAY : ")
// print(binaryString)
return binaryString
}
I would try this extension to NSData that provides a CollectionType interface. It seems like it would make it much easier for you to do your modifications without having to much around with UnsafeMutablePointer:
Bytes collection for NSData
Since BytesView and MutableBytesView are a CollectionType it gives you subscripting, indices, and more so you can iterate through your data and make the changes you want.
The article which is relevant to this question and introduces that linked code:
NSData, My Old Friend