Unable to add object to a NSMutableArray - swift

I'm attempting to load a mutable array and got stuck.
Essentially what I want to do is to be able to add any class object to a global array. In this example I merely have name & address.
Here's a playground snippet:
import Foundation
var gDownloaders:NSMutableArray?
class downloader {
var name:String?
var address:String?
init(name:String, address:String) {
self.name = name
self.address = address
}
}
let one = downloader(name: "Ric Lee", address: "901 Edgewood")
let two = downloader(name: "Richard Brauer", address:"1010 Red Oak")
let three = downloader(name: "Meredith Lind", address: "410 Sunset Blvd")
gDownloaders?.addObject(one)
gDownloaders?.addObject(two)
gDownloaders?.addObject(three)
println(gDownloaders)
BTW: Xcode insist that I have the '?'/gDownloaders.
All I'm getting is nil for gDownloaders; even though each of the three objects are bona fide with data.
What am I doing wrong?
...should I use the Array vs NSMutableArray class instead?

You never initialize gDownloaders. You declare what type the variable gDownloaders should have, but you don't put anything in that variable.
Try:
var gDownloaders:NSMutableArray? = NSMutableArray()

In swift, in a playground try this:
import Foundation
class downloader {
var name:String?
var address:String?
init(name:String, address:String) {
self.name = name
self.address = address
}
}
var gDownloaders = [downloader]()
let one = downloader(name: "Ric Lee", address: "901 Edgewood")
let two = downloader(name: "Richard Brauer", address:"1010 Red Oak")
let three = downloader(name: "Meredith Lind", address: "410 Sunset Blvd")
gDownloaders.append(one)
gDownloaders.append(two)
gDownloaders.append(three)
println(gDownloaders[0].name!)

Related

Why is this showing 'Expected 'func' keyword in instance method declaration'

I'm new to coding and using SwiftUI on Xcode, and I don't see what's wrong with this code:
class NormalSpace {
var name = ""
var value = 0
var rent = 0
var owned = false
}
var newRoad = NormalSpace()
newRoad.name = "New Road"
newRoad.value = 600
newRoad.rent = 25
newRoad.owned = false
the error 'Expected 'func' keyword in instance method declaration' only shows on the newRoad.name line. The same line also has the error: Invalid redeclaration of 'newRoad'.
What have I done wrong?
In an normal project, this is not valid:
class NormalSpace {
var name = ""
var value = 0
var rent = 0
var owned = false
}
var newRoad = NormalSpace()
newRoad.name = "New Road"
newRoad.value = 600
newRoad.rent = 25
newRoad.owned = false
You can do that in a playground (where it just runs this code directly), but in an app, code (such as the setting of the properties) belongs in a function or initializer.
That initialization code needs to be placed within some context. Let us imagine that it is inside a struct. But this still is not valid:
class NormalSpace {
var name = ""
var value = 0
var rent = 0
var owned = false
}
struct Foo {
var newRoad = NormalSpace()
newRoad.name = "New Road"
newRoad.value = 600
newRoad.rent = 25
newRoad.owned = false
}
The property, newRoad is fine, but the values are not. You need to wrap it inside a func (hence the error) or an init. E.g., this initializes newRoad during the init of the struct:
struct Foo {
let newRoad: NormalSpace
init() {
newRoad = NormalSpace()
newRoad.name = "New Road"
newRoad.value = 600
newRoad.rent = 25
newRoad.owned = false
}
}
Or you might initialize it in a func:
struct Foo {
var newRoad: NormalSpace?
mutating func bar() {
let road = NormalSpace()
road.name = "New Road"
road.value = 600
road.rent = 25
road.owned = false
newRoad = road
}
}
Or, alternatively, you can initialize this property with a closure (note the extra () at the end):
struct Foo {
let newRoad: NormalSpace = {
let road = NormalSpace()
road.name = "New Road"
road.value = 600
road.rent = 25
road.owned = false
return road
}()
}
But the code where you initialize the properties must be placed within some context, so that the compiler knows when those lines of code should be run.
Note, we would generally give NormalSpace a “memberwise initializer”, e.g.:
class NormalSpace {
let name: String
let value: Int
let rent: Int
let owned: Bool
init(name: String, value: Int, rent: Int, owned: Bool) {
self.name = name
self.value = value
self.rent = rent
self.owned = owned
}
}
Or, if a struct (and we would generally prefer to make our model objects struct value-types rather than class reference-types), this memberwise initializer would be created for you:
struct NormalSpace {
let name: String
let value: Int
let rent: Int
let owned: Bool
}
Either way, you can then provide all the desired values during initialization, e.g.:
struct Foo {
let newRoad = NormalSpace(name: "New Road", value: 600, rent: 25, owned: false)
}
Note, that I've removed the “default” values because those really are not appropriate. If you wanted to say that they do not need to be provided, then you would make them “optionals”. But there is generally a big difference between, say, a rent of zero (i.e. it is my grandmother’s house and she's not charging me) and that no rent has been specified. In Swift, we generally avoid using “sentinel” values like "" or 0 for “no value provided”.
Also, now that we have a memberwise initializer, I have also made the properties immutable (let rather than var). If you need to make them mutable (e.g. to let someone change the rent later), fine, revert back to var. But only make properties mutable if you really need to change them later on.

How can I refer to properties from a struct within a struct/

I'm trying to get the hang of how to make my code the most efficient using Structs / Classes, and I'm trying to understand it via the following example.
I'd be really grateful if someone could correct me or guide me about the same:
Just as an example, I'll use Harry Potter. There are four houses, and each house has certain characteristics.
So now I have a struct for 2 of them:
struct Gryffindor {
let name = "Gryffindor"
let characteristic = "Brave"
let image = Image("Lion")
}
struct Slytherin {
let name = "Slytherin"
let characteristic = "Cunning"
let image = Image("Snake")
}
Now if I wish to have a wizard struct as follows, but I don't know how to include a House property within, such that when I try to create an instance of a wizard, I can call the properties from their respective houses.
struct Wizard {
let name: String
var house: ?
}
let harryPotter = Wizard(name: "Harry", house: Gryffindor)
Basically, I wish to be able to refer to harry's house using the harryPotter instance, as such:
print(harryPotter.characteristic) //should print "Brave"
Is what I'm trying to achieve even possible?
First of all you are mixing types with objects so you should have a type House
struct House {
let name: String
let characteristic: String
let image: Image
}
And then use that in the Wizard struct
struct Wizard {
let name: String
var house: House
}
And now you create first a House object for the Wizard and then the Wizard object
let gryffindor = House(name: "Gryffindor", characteristic: "Brave", image: Image("Lion"))
let harryPotter = Wizard(name: "Harry", house: gryffindor)
or all in one call
let harryPotter = Wizard(name: "Harry",
house: House(name: "Gryffindor", characteristic: "Brave", image: Image("Lion")))
Use protocol & generics, like below. Tested with Xcode 11.4.
protocol House {
var name: String { get }
var characteristic: String { get }
var image: Image { get }
}
struct Gryffindor: House {
let name = "Gryffindor"
let characteristic = "Brave"
let image = Image("Lion")
}
struct Wizard<H: House> {
let name: String
var house: H
}
let harryPotter = Wizard(name: "Harry", house: Gryffindor())

class in playground vs in program file

I have a question about something simple that works in Playground but not in a Project: (Playground code below)
In the project where the class is in a separate swift file the code correction won't show me the the person.lastName and if I fully type it give me an error.... hmm, very strange - might be a beginner error or?
How would I have to state in in the program file and the separate swift file to work?
Thanks,
Roman
import UIKit
class human {
var firstName = ""
var lastName = ""
}
let person = human()
person.lastName = "Smith"
person.firstName = "Peter"
print (person.firstName)
print (person.lastName)
This is why I hate playgrounds. They are not really Swift. In real Swift, all executable code must be inside a function (e.g. a method of some class or struct or enum); you can't have lines like person.lastName = "Smith" just hanging in space like that.
So in a real iOS project you'd need to write something more like this:
class Human {
var firstName = ""
var lastName = ""
}
func test() {
let person = Human()
person.lastName = "Smith"
person.firstName = "Peter"
print (person.firstName)
print (person.lastName)
}
And even then nothing would happen until you actually call test(), and you can't do that except in a function. This is why people usually test code in the viewDidLoad of a view controller.
class Human {
var firstName = ""
var lastName = ""
}
class ViewController : UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let person = Human()
person.lastName = "Smith"
person.firstName = "Peter"
print (person.firstName)
print (person.lastName)
}
}

Generic Type array with UITableView and Realm

I am using realm for database. I have Favourite Object and History Object.
I want to show in TableViewController. However, I don't want to do duplicated code. For now, in FavouriteViewController , it has var favs: Results<OGFav>? and HistoryViewController, it has var history: Results<OGHistory>?
Most of the code are the same and different is data type.
Example: it only different like following
if let object:OGFav = self.favs?[indexPath.row] {
In some place , I use like
let fav:OGFav = favs[indexPath.row]
For History
if let object:OGHistory = self.history?[indexPath.row] {
History also use like below
let history:OGHistory = self.history[indexPath.row]
How can I clean the code ? I am using two viewcontroller and code are the same excepted OGFav and OGHistory.
Update:
OGFav and OGHistory have the same data.
class OGFav: Object {
dynamic var word = ""
dynamic var def = ""
}
class OGHistory: Object {
dynamic var word = ""
dynamic var def = ""
dynamic var updatedAt = NSDate()
}

No Class/Struct Autocomplete in Swift

I currently have two structs and a class in my sample code. One struct is for Tiger, one is for Balloon and on is for Lion. Each are below:
struct Tiger {
var name = ""
var age = 0
var breed = ""
var image = UIImage(named: "")
func chuff() {
println("\(name): Chuff Chuff")
}
func chuffNumberOfTimes(numberOfTimes:Int) {
for (var i = 0; i < numberOfTimes; i++) {
self.chuff()
}
}
func ageInTigerYearsFromAge(regularAge:Int) -> Int {
return regularAge * 3
}
func randomFact() -> String {
let randomFactNumber = Int(arc4random_uniform(UInt32(3)))
var randomFact:String
switch randomFactNumber {
case 0:
randomFact = "Tigers are 10 feet tall."
case 1:
randomFact = "Tigers are amazing."
case 2:
randomFact = "Tigers have 10 feet."
default:
randomFact = ""
}
return randomFact
}
}
struct Balloon {
var number = 0
var image = UIImage(named: "")
}
class Lion {
var name = ""
var age = 0
var isAlphaMale = false
var image = UIImage(named: "")
var subSpecies = ""
}
Each one is in its own file named identically to the struct/class & ".swift". However, the only one that autocompletes itself while typing in ViewController.swift is the Tiger struct. For instance, if I were to set myTiger = Tiger( it would suggest name: String, age: Int etc. How can I get the other two to do the same? I really like defining the variables inline instead of having 5 lines of code to define all of the variables.
Is anyone familiar with how that works or why the Tiger struct would do it while the Balloon and Lion structs don't?
Classes don't get the initializers for free as the Struct does, if you want to have an initializer for a class you have to create it:
class Lion {
var name = ""
var age = 0
var isAlphaMale = false
var image = UIImage(named: "")
var subSpecies = ""
init(name: String, age:Int, isAlphaMale: Boolean, image: UIImage, subSpecies: String){
self.name = name
self.age = age
self.isAlphaMale = isAlphaMale
self.image = image
self.subSpecies = subSpecies
}
}
The Balloon should work automatically, probably a clean and build in your code so xcode can be updated will fix the problem.
From Apple Documentation:
Memberwise Initializers for Structure Types
All structures have an automatically-generated memberwise initializer,
which you can use to initialize the member properties of new structure
instances. Initial values for the properties of the new instance can
be passed to the memberwise initializer by name:
copied from a previus part of the document to add context
struct Resolution {
var width = 0
var height = 0
}
let vga = Resolution(width: 640, height: 480)
Unlike structures, class
instances do not receive a default memberwise initializer.
With the class above you will have the initializer as in the screenshot below:
As you can see in the screenshot Balloon works perfectly fine as well
No need to enter once to start work, xcode is not perfect and sometimes it needs a clean and a new build to make it be in sync with your classes and structs.