I'm new to Swift and I'm not sure how I can pick up a file and store it in a binary array.
I do know how to pick up a file, but I don't know how I can store it in a binary array which would be modified later.
Suppose the variable "chosenFile" is the file I pick up ( in NSData type)
And the variable "bArray" ( [int8] array) is the array used to store the binary representation of the file.
var bArray: [Int8] = [Int8]()
var chosenFile: NSData! = NSData(contentsOfURL: "xxxxxxxx")
Any help ?
If you create an instance of NSMutableData, you can use the mutableBytes property to get a reference to the underlying data. In C, this would be a void *; in Swift, it is an UnsafeMutablePointer<Void>.
You can then work with this data directly (there's no need for another byte array). So long as you stay within the length of the NSMutableData, you can, eg, replace individual bits of data, or indeed the entirety of the data.
Alternatively, rather than working on the primitive directly, you can use replaceBytesInRange:withBytes: to selectively modify part of your data. This is also explained in the documentation.
Related
What are the inner workings?
Does it create a Swift string copy of the C string data?
Does it use it as a reference and return it as a Swift string, so the string returned uses the same data? How does it work?
Does it copy the C string into a newly allocated Swift string?
If String(cString: UnsafePointer<Int8>) indeed works by copying the C string into a newly allocated swift string, is there a way to convert C strings to swift by referencing the already existing data instead of copying it?
How does String(cString: UnsafePointer<Int8>) work, and how can I determine whether it copies, or whether it references the same memory as a Swift string?
The documentation clearly states that the data is copied:
Initializer
init(cString:)
Creates a new string by copying the null-terminated UTF-8 data referenced by the given pointer.
is there a way to convert C strings to swift by referencing the already existing data instead of copying it?
Nope. Strings are frequently copied/destroyed, which involves doing retain/release operations on the underlying buffer, to do the necessary booking keeping of thethe reference count. If the memory is not owned by the String, then there's no way to reliably de-allocate it.
What are you trying to achieve by avoiding the copy?
In Swift I am trying to create an AUSamplerBankPresetData object which requires an Unmanaged<CFURL> object.
How do I convert a URL object into Unmanaged<CFURL> in swift?
You first need to convert your URL into a CFURL. This can be done with an unconditional cast so:
let cfurl = url as CFURL
Then, to create an unmanaged reference to that CFURL you'll need to use one of the functions outlined here to create an Unmanaged object. Make sure you choose the right one for your application. The example below will increment the reference count, so you will need to make sure that it is decremented later.
var um = Unmanaged<CFURL>.passRetained(cfurl)
We all know an array in swift is a value type, this means after copying or assigning an array to another, modify the new array will not effect the old one. Such as:
var a = ["a", "b", "c", "d", "e"]
var b = a
b[0] = "1"
print(a[0]) // a
print(b[0]) // 1
But I'm wondering how could an array work like that. The length for a 'var' array is dynamical. Usually we must alloc some heap memory to contain all the values. And I do peek some source codes for struct Array, the underlining buffer for an array is implemented using a class. But when copying a struct which contains class or memory pointer member, the class and alloced memory will not copied by default.
So how could an array copy its buffer when copy or assign it to another one?
Assignment of any struct (such as Array) causes a shallow copy of the structure contents. There's no special behavior for Array. The buffer that stores the Array's elements is not actually part of the structure. A pointer to that buffer, stored on the heap, is part of the Array structure, meaning that upon assignment, the buffer pointer is copied, but it still points to the same buffer.
All mutating operations on Array do a check to see if the buffer is uniquely referenced. If so, then the algorithm proceeds. Otherwise, a copy of the buffer is made, and the pointer to the new buffer is saved to that Array instance, then the algorithm proceeds as previously. This is called Copy on Write (CoW). Notice that it's not an automatic feature of all value types. It is merely a manually implemented feature of a few standard library types (like Array, Set, Dictionary, String, and others). You could even implement it yourself for your own types.
When CoW occurs, it does not do any deep copying. It will copy values, which means:
In the case of value types (struct, enum, tuples), the values are the struct/enum/tuples themselves. In this case, a deep and shallow copy are the same thing.
In the case of reference types (class), the value being copied is the reference. The referenced object is not copied. The same object is pointed to by both the old and copied reference. Thus, it's a shallow copy.
On Apple's documentation on Substring, is says:
Don’t store substrings longer than you need them to perform a specific operation. A substring holds a reference to the entire storage of the string it comes from, not just to the portion it presents, even when there is no other reference to the original string. Storing substrings may, therefore, prolong the lifetime of string data that is no longer otherwise accessible, which can appear to be memory leakage.
I feel confused that String is a value type in Swift and how does it lead to memory leak?
Swift Arrays, Sets, Dictionaries and Strings have value semantics, but they're actually copy-on-write wrappers for reference types. In other words, they're all struct wrappers around a class. This allows the following to work without making a copy:
let foo = "ABCDEFG"
let bar = foo
When you write to a String, it uses the standard library function isUniquelyReferencedNonObjC (unless it's been renamed again) to check if there are multiple references to the backing object. If so, it creates a copy before modifying it.
var foo = "ABCDEFG"
var bar = foo // no copy (yet)
bar += "HIJK" // backing object copied to keep foo and bar independent
When you use a Substring (or array slice), you get a reference to the entire backing object rather than just the bit that you want. This means that if you have a very large string and you have a substring of just 4 characters, as long as the substring is live, you're holding the entire string backing buffer in memory. This is the leak that this warns you about.
Given the way Swift is often portrayed your confusion is understandable. Types such as String, Array and Dictionary present value semantics but are library types constructed from a combination of value and references types.
The implementation of these types use dynamically allocated storage. This storage can be shared between different values. However library facilities are used to implement copy-on-write so that such shared storage is copied as needed to maintain value semantics, that is behaviour like that of value types.
HTH
I have a Class for handling my data in my project, and now I need to store the data.
I'd like to use a Plist but I'm a bit unsure of how to start.
My class is pretty simple - 6 pieces of data, flat (no hierarchy).
I want my app to start with no data, so can I assume that I should create the PList programmatically once the User creates their first piece of data? (That is, don't create a .plist file in 'Supporting Files' prior to distribution?)
Then, when the app starts the next time, read the data and create an NSMUtableArray array of Class instances?
To create a property list, all you need to do is use appropriate types (i.e. those that support the property list format: NSData, NSString, NSDictionary, NSNumber, NSDate, NSArray), store them in a single container, and tell the containing object to write itself to a file. To read the data, you can initialize that same type using a path. For example:
// writing some data to a property list
NSString *somePath = ... // replace ... with the path where you want to store the plist file
NSMutableDictionary myDict = [NSMutableDictionary dictionary];
[myDict setObject:#"Caleb" forKey:#"name"];
[myDict setObject:[NSNumber numberWithInt:240] forKey:#"cholesterolOrIQ"];
[myDict writeToFile:somePath atomically:YES];
// reading the file again
NSDictionary *readDict = [NSDictionary dictionaryWithContentsOfFile:somePath];
The simplest way is to simple save an NSArray or NSDictionary to disk. Caleb's answer goes into detail there so I won't repeat it, other than to say you might have to convert a non-compatible object like NSColor to an property list object like NSData. It's up to you to do this each time you save or load your data.
NSKeyedArchiver and NSKeyedUnarchiver give you a little more control over the process, but work pretty much the same way. You provide (or get back) a plist compatible root object (usually an NSDictionary) that contains your data. I recommend creating a dictionary that includes your data structure as well as an arbitrary number (your app's build number is a good choice) to use as a version indicator. This way if you ever update your data model you can easily determine if you need to do anything to convert it to the new version.
If you're putting your own objects into the data file, look into NSCoding. The protocol gives you two methods using NSKeyedArchiver and NSKeyedUnarchiver to save and restore your data. This is by far the most straightforward approach if your data model consists of anything more than a few simple strings and numbers, since you're dealing with your own native objects. In your case, you would have your data class implement NSCoding and use the NSKeyedArchiver and NSKeyedUnarchiver methods to encode your six instance variables. When it's time to save or load, pack the instance of your class into an NSDictionary (along with a versioning number as I mentioned above) and call NSKeyedArchiver's archiveRootObject:toFile:. Your save an load methods deal only with your own data object, which makes things easy for you. The common pitfall to watch out for here is if your custom data object contains other custom object. This is fine, but you have to make sure every object that's going to be saved has its own NSCoding implementation.
Two things you can do:
Use NSUserDefaults:
http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/NSUserDefaults_Class/Reference/Reference.html
The objectForKey method is the one you want to use to store your class. But, as pointed out in the comments, this shouldn't really be used for storing lots of user data; it's best for saving preferences.
For storing more data, you might want to look at Core Data. It's more complex, but should be better suited to your needs. Here's a tutorial on it:
http://mobile.tutsplus.com/tutorials/iphone/iphone-core-data/
Neither of these seems best for your simple application, but I leave this answer up since it gives alternatives for saving data to the iPhone.