Append a class object to an array - swift

I am having trouble with the syntax here. Basically I created a simple class and hoping to add the object of that class to an Array.
class simpleClass {
var aNum = Int()
var aWord = String()
init(thisNum:Int,thisString:String)
{
aNum = thisNum
aWord = thisString
}
}
var aObj:simpleClass
var aArray:Array<simpleClass>
aObj = simpleClass(thisNum:12,thisString:"Test")
aArray.append(aObj)
As you can see I have created an object of simpleClass and trying to append it to an array of type simpleClass. However, I receive an error saying
passed by reference before being initialized
I guess I must be missing something in the syntax. Hoping someone out there could point out my mistake.
thanks,
sweekim

You need to assign an array to the array variable.
var aArray:Array<simpleClass> = []
Or if you prefer,
var aArray = Array<simpleClass>()
Or even (my preference)
var aArray: [simpleClass] = []
Or
var aArray = [simpleClass]()
Better yet you could even reorder things and do this:
var aArray = [simpleClass(thisNum:12,thisString:"Test")]
instead of the whole 4 last lines.
Incidentally, you might find it better to declare your class like this:
class simpleClass {
var aNum: Int
var aWord: String
init(thisNum:Int,thisString:String) {
aNum = thisNum
aWord = thisString
}
}
This types aNum and aWord, but does not assign them values, since you then do that in the init method. The reason being, if you ever forgot to assign a value in init the compiler will warn you, whereas if you default them, it won’t. It’s fine to default them instead, but then don’t include them in an init method – one or the other is best, both is a bit redundant and can lead to mistakes.

Change this line:
var aArray:Array<simpleClass>
To this:
var aArray:Array<simpleClass> = []
You were declaring the array type but you forgot to make any array. If you actually look at the error message, it tells you exactly that - you didn't initialize the variable.

Also I think you didn't quite declare your instance of simpleClass correctly. I did this to silence the errors:
var aArray:Array<simpleClass> = []
let aObj:simpleClass = simpleClass(thisNum:12,thisString:"Test")
aArray.append(aObj)
Note the way an instance of simpleClass is created.

Related

How to use a value type object as a reference type?

In my model, I have some arrays:
var thisArray = [Object]
var thatArray = [Object]
var anotherArray = [Object]
In my view controller, I want to switch on a value to determine which array I will append to:
var whichArray: [Object]!
switch someValue {
case .thisArray: whichArray = thisArray
case .thatArray: whichArray = thatArray // "He went thatArray!"
case .anotherArray: whichArray = anotherArray
}
whichArray.append(object)
But of course this won't work because Array is a value type.
Is there a way to do this? Of course I could do the following:
switch someValue {
case .thisArray: thisArray.append(object)
case .thatArray: thatArray.append(object)
case .anotherArray: anotherArray.append(object)
}
But that is so inelegant and redundant! And if there's other more complex things going on in the surrounding code, then it's especially so.
Is there a solution here? Is it possible to create a reference to a value type?
PS. Even better, though really its own question, is if I could use the name of the case (e.g., "thisArray" for someValue = .thisArray) to set the array, by name (i.e., avoid the whole switch statement and just say objectName.append(object) or something like that) but as far as I know this isn't a thing. Or maybe this IS possible? And maybe it's my birthday?
Since Arrays are value types - as you have said yourself - they can't be passed around (or assigned) as a reference. One solution would be to create a wrapper class for the Array which itself would then be a reference type. You can then assign this wrapper class instead of the arrays themselves.
Now, given that you also said you might prefer to access the Arrays by the name and completely get rid of the switch you could change your design to storing thisArray, thatArray and anotherArray in a Dictionary, with the keys being the different values for someValue.
This way you could simply append to the desired array with:
arrayDict[someValue]?.append(object)
(Given that you've properly set up the dictionary beforehand)
Like this for example:
enum Value {
case thisArray
case thatArray
case anotherArray
}
var arrayDict = [
Value.thisArray : [String](),
Value.thatArray : [String](),
Value.anotherArray : [String]()
]
arrayDict[.thatArray]?.append("Some String.")
For the sake of creating a short working example I've replaced Object with String but that obviously doesn't matter.
I would typically recommend solving this with closures. It's more powerful and safer. For example:
let append: (Object) -> Void
switch someValue {
case .thisArray: append = { thisArray.append($0) }
case .thatArray: append = { thatArray.append($0) }
case .anotherArray: append = { anotherArray.append($0) }
}
append(object)
(It would be ideal here to just say append = thisArray.append, but you can't do that in Swift today. It's a "partial application of a mutating function" and that's not currently legal.)
Even though Swift was designed to reduce pointer operations, pointers are still available:
var thisArray = [1,2,3]
var thatArray = [4,5,6]
var anotherArray = [7,8,9]
var ptr: UnsafeMutablePointer<[Int]>
let someValue = 2
switch someValue {
case 1: ptr = UnsafeMutablePointer(&thisArray)
case 2: ptr = UnsafeMutablePointer(&thatArray)
default: ptr = UnsafeMutablePointer(&anotherArray)
}
ptr.pointee.append(42)
print(thatArray) // [4,5,6,42]
A minor annoyance with this is that you have to call ptr.pointee to access the target array. If you assign the pointee to another variable (i.e. let whichArray = ptr.pointee), any modification to whichArray won't be reflected in the original array.
(I had to change your Object type to Int so that it runs in the IBM Swift Sandbox)

Cannot assign to property: function call returns immutable value

Consider the following example.
struct AStruct{
var i = 0
}
class AClass{
var i = 0
var a: A = A(i: 8)
func aStruct() -> AStruct{
return a
}
}
If I try to mutate the the variable of a instance of class AClass it compiles successfully.
var ca = AClass()
ca.a.i = 7
But If I try to mutate the return value of aStruct method, the compile screams
ca.aStruct().i = 8 //Compile error. Cannot assign to property: function call returns immutable value.
Can someone explain this.
This is compiler's way of telling you that the modification of the struct is useless.
Here is what happens: when you call aStruct(), a copy of A is passed back to you. This copy is temporary. You can examine its fields, or assign it to a variable (in which case you would be able to access your modifications back). If the compiler would let you make modifications to this temporary structure, you would have no way of accessing them back. That is why the compiler is certain that this is a programming error.
Try this.
var aValue = ca.aStruct()
aValue.i = 9
Explanation
aStruct() actually returns a copy of the original struct a. it will implicitly be treated as a constant unless you assign it a var.
Try using a class instead of a struct, as it's passed by reference and holds onto the object, while a struct is passed by value (a copy is created).

Difference between various type of Variable declaration in swift

I am quite a confused when and how to declare variables in particular points in Swift and its causing a headache for a new guy like me in SWIFT.
What is the difference between the following type of declarations? I have given my thoughts and understanding on them. Please rectify me with your solution if I am wrong and be a bit explanatory so that I can know the actual and exact answer.
Array -
1) var arr = NSArray()//I think its an instance of immutable NSArray type
2) var arr = NSMutableArray()
3) var arr = Array()//I have no idea of difference between NSArray and Array type. Might be both are same
4) var arr : NSMutableArray?//Creates an optional type but how is it different from line no.2
5) var arr : NSMutableArray = []//creates an empty array NSMutableArray type and again how is it different from line no.2 & 3
Please clarify a bit clearly so that my confusion level would be a bit clear. Thanks
Array is a swift type where as NSArray is an objective C type. NS classes support dynamic-dispatch and technically are slightly slower to access than pure swift classes.
1) var arr = NSArray()
arr is an NSArray() here - you can re-assign things to arr but you can't change the contents of the NSArray() - this is a bad choice to use IMO because you've put an unusable array into the variable. I really can't think of a reason you would want to make this call.
2) var arr = NSMutableArray()
Here you have something usable. because the array is mutable you can add and remove items from it
3) var arr = Array()
This won't compile - but var arr = Array<Int>() will.
Array takes a generic element type ( as seen below)
public struct Array<Element> : CollectionType, MutableCollectionType, _DestructorSafeContainer {
/// Always zero, which is the index of the first element when non-empty.
public var startIndex: Int { get }
/// A "past-the-end" element index; the successor of the last valid
/// subscript argument.
public var endIndex: Int { get }
public subscript (index: Int) -> Element
public subscript (subRange: Range<Int>) -> ArraySlice<Element>
}
4) var arr : NSMutableArray?
You are defining an optional array here. This means that arr starts out with a value of nil and you an assign an array to it if you want later - or just keep it as nil. The advantage here is that in your class/struct you won't actually have to set a value for arr in your initializer
5) var arr : NSMutableArray = []
It sounds like you are hung up on confusion about Optional values.
Optional means it could be nil or it could not
When you type something as type? that means it is nil unless you assign it something, and as such you have to unwrap it to access the values and work with it.
#G.Abhisek at first about you question. var arr: NSMutableArray = [] and var arr = NSMutableArray() means the same. the first one means, i ask the compiler to create a variable of type NSMutableArray and initialize it as an empty NSMutableArray. the second one means, i ask the compiler to create a variable and assign to it an empty initialized NSMutableArray. in the second case the compiler has to infer the right type of the variable, in the first case i did it by myself. still, the result will be the same. var arr1: Array<AnyObject> = [] and var arr2: NSMutableArray = [] are totally different things!. arr1 srores value type Array, arr2 stores reference to the instance of an empty NSMutableArray class. you can write let arr2: NSMutableArray = [] and next you can add an object there ... but you are not able to do thinks like arr2 = ["a","b"]. arr2 is constant, not variable, so the value stored there is imutable.
i am again close to my computer ... in the code below, you can see the main differences between swift and foundation arrays
import Foundation
let arr1: NSMutableArray = []
arr1.addObject("a")
arr1.addObject(10)
arr1.forEach {
print($0, $0.dynamicType)
/*
a _NSContiguousString
10 __NSCFNumber
*/
}
var arr2: Array<Any> = []
arr2.append("a")
arr2.append(10)
arr2.forEach {
print($0, $0.dynamicType)
/*
a String
10 Int
*/
}
var arr3: Array<AnyObject> = []
arr3.append("a")
arr3.append(10)
arr3.forEach {
print($0, $0.dynamicType)
/*
a _NSContiguousString
10 __NSCFNumber
*/
}
print(arr1.dynamicType, arr2.dynamicType, arr3.dynamicType)
// __NSArrayM Array<protocol<>> Array<AnyObject>

Access Class In A Dictionary - Swift

I am now writing a program involves class and dictionaries. I wonder how could I access a class's values inside a dictionary. For the code below how do I access the test1 value using the dictionary. I have tried using dict[1].test1but it doesn't work.
class test {
var tes1 = 1
}
var refer = test()
var dict = [1:refer]
There are a few problems with the line dict[1].test1:
Firstly, the subscript on a dictionary returns an optional type because there may not be a value for the key. Therefore you need to check a value exists for that key.
Secondly, in your class Test you've defined a variable tes1, but you're asking for test1 from your Dictionary. This was possibly just a type-o though.
To solve these problems you're code should look something like this:
if let referFromDictionary = dict[1] {
prinln(referFromDictionary.test1)
}
That's because the subscript returns an optional, so you have to unwrap it - and the most straightforward way is by using optional chaining:
dict[1]?.tes1
but you can also use optional binding:
if let test = dict[1] {
let value = test.tes1
}

Howto reference an Array in swift

I would like to have a reference to an array for better coding, but I don't know howto do. The following code should illustrate what I mean:
I have a class, with an Array of Array of Objects as follow:
class Group: NSObject {
var alGroup = [[NSObject]]();
}
I have the following 2 different codes from which I would like to prefer using the first one.
code 1, which doesn't work with a reference to the inner array. With not working I mean the object is lost (no syntax or runtime error) :
func addObjectto_new_Group(o:NSObject, inout group:Group){
var alGroup = group.alGroup;
var alNew = [NSObject]();
alNew.append(o);
//group.alGroup.append(alNew);
alGroup.append(alNew);
}
Code 2, which works, but not preferred:
func addObjectto_new_Group(o:NSObject, inout group:Group){
//var alGroup = group.alGroup;
var alNew = [NSObject]();
alNew.append(o);
group.alGroup.append(alNew);
//alGroup.append(alNew);
}
How can I have a reference to an array like in code 1 ?
When you create your 'alias' variable var alGroup = group.alGroup you do not copy by reference, but by value as explained in the comments to your question. So one way to solve this is to use the full name like in group.alGroup.append(alNew).
However there is a another option which might be to your liking:
func addObjectToNewAlGroup(o:NSObject, inout alGroup : [[NSObject]])
{
var alNew = [NSObject]()
alNew.append(o)
alGroup.append(alNew)
}
var aGroup = Group()
addObjectto_new_Group("a1", &aGroup)
addObjectto_new_Group("b2", &aGroup)
addObjectToNewAlGroup("c3", &aGroup.alGroup)
This uses your 'Code 2' version, and a new function doing the same, but passing the array by reference into the function. This is legal, and does work. It is only references within a function which doesn't work as you want.