Weak object array in Swift - ios

I would like to create an object array as a property of another class in Swift, such as:
class person{
var livingInHouse : house
name : String
}
class house{
var personArray : [person]
}
My constraints are:
I would like to easily access the objects in the personArray using subscripts: e.g. houseInstance.personArray[1].name = "Steve"
I would like to create the personArray so that the person objects are deallocated when houseInstance object is deallocated.
What is the best method in Swift to do this?

From what you say, you want the person living in an house "alive" as long as their house is alive, so it is obvious that the house must "own" the persons.
Your class Person however just maintain a reference to the house for convenience, it doesn't own it (else it would be bad!)
so :
class house
{
var personArray : person[]
}
class person
{
unowned var livingInHouse : house
name : String
}
You could then provide some convenience method to your house such as:
func add(Person p)
{
personArray += p;
p.livingHouse = self;
}

Related

Some mistakes in the language

I'm new in Dart, I want to precise this. I create two classes in Dart, one is 'Person' and the other one is a child of the first one, and it's named 'Employee'.
I create an object of Person. When I change this object to an Instance of class Employee, nothing wrong. But at the time that I'm asking to a parameter that is inside the Employee, I raised an error.
So why Dart allow me to the class of the object, but not allowed me to access to a parameter inside the new class?
The code below :
void main {
var person = Person(name: "Zozor");
print(person.describe());
person = Employee(taxCode: 'AAB');
person.sayName();
print(person.taxCode);
}
class Person {
Person({this.name, this.age, this.height});
String name;
final int age;
final double height;
String describe() => "Hello, I'm ${this.name}. I'm ${this.age} and I'm ${this.height} meter${this.height == 1 ? '':'s'} tall";
void sayName()=> print("Hello, I'm ${this.name}.");
}
class Employee extends Person {
Employee({String name, int age, double height, this.taxCode, this.salary}) : super(name:name, age: age, height: height);
final String taxCode;
final int salary;
}
Variables in Dart must be declared before being used. They have a type and store a reference to the value (see https://www.tutorialspoint.com/dart_programming/dart_programming_variables.htm).
var person = Person(name: "Zozor");
Declares the variable person of type Person (type is derived from the type of class it is initialized to).
When you assign:
person = Employee(taxCode: 'AAB');
The type is unchanged with the assignment (i.e. remains Person), only the reference changes to the result of downcasting the Employee to a Person (the downcasting is done implicitly as described https://news.dartlang.org/2012/05/types-and-casting-in-dart.html).
The above is due to var creating static type variables.
An alternative would be to use dynamic typing as in:
dynamic person = Person(name: "Zozor");
This declares a person variables whose type is dynamic. Now when the assignment is made to Employee:
person = Employee(taxCode: 'AAB');
The type of the person variable is now Employee rather than Person. Furthermore, there is no downcasting of Employee and no error message related to taxCode.
A simple way to stay with static (rather than using dynamic) is to use an explicit recasting of person to Employee:
print((person as Employee).taxCode);
This casts a person to Employee then gets the taxCode.

Setter/Getter in protocol in swift

branchID is set to be a getter BUT I am able to set the value. What is the use of specifying it to be a setter/ getter?
protocol Bank {
var name: String {get set}
var branchID: Int {get}
}
struct Person: Bank {enter code here
var name: String = "ABC Bank"
var branchID: Int = 123
}
let person = Person()
person.name
person.branchID
First of all the code doesn't use the protocol.
If an object adopts a protocol it must implement the protocol requirements. Your code creates an object Person with all capabilities of Person
var person = Person()
and you can change branchID
person.branchID = 13
However if you cast person to Bank
var bank = person as Bank
bank.branchID = 13
you will get the error
Cannot assign to property: 'branchID' is a get-only property
The same error occurs if you declare a function which tries to update all objects which conform to Bank
func updateID(item : Bank)
{
item.branchID = 12
}
branchID in Person is a new object,You can certainly change its value.
when you write 'Bank. branchID',you can't set its value

Will an array of a superclass contain subclasses as well?

I created a class Person. Person contain properties like name and email. Both are from type String.
Beside the Person class, I have a subclass Student that inherited from superclass Person. Subclass Student contain properties like student number (String) and isGraduated (Boolean).
I have an empty array of persons from the class Person, like:
var persons: [Person]()
After I created both Person and Student objects inside the array persons, I read them out using a UITableView. Both models will be print in the cells. But when I want to check the value of isGraduated from the selected row, auto-completion doesn't give me the value of the property: persons.isGraduated.
The first thought of this problem is, will my persons array contain also the subclass Student? My second thought would be, that I think I should not check the value isGraduated inside the TableView. My wish of this function is that it will do something, like call the native camera if the person is graduated.
Looking forward to the solution.
Tree options here
A: Change the array type to Student
var students: [Student]()
B: Cast each element from the persons array to a Student. Ideally inside a for each person.
guard let student = person as? Student else {
return // or continue if inside a for loop
}
Then u will have access to that student variable.
C: Or if they might be students and persons at the same time in the array then
for person in persons {
switch person{
case let student as Student: //student case
//do something
default: //person case
//do something
}
}
If you want to check what is the type of your person : Person or Student you can use is keyword like this :
if persons[0] is Person {
//if a person
} else if persons[0] is Student {
//if a student
}
If you want to use a function member for your specific type, you need to downcast the type by using the keyword as like this :
if let person = persons[0] as? Person {
//person is now a Person type
} else if let student = persons[0] as? Student {
//student is now a Student type
}

Adding An Item To An NSSet For A Core Data One To Many Relationship

I have a core data relationship where one entity holds many of another entity. As far as I am aware each instance of the many class is held inside an NSSet? inside the one class. (?)
My question is - what is the best way to add items to this set? I figure this must be a very common problem - but I cannot seem to find an easy method.
This is my attempt: (This is all taken from the one class)
static var timeSlotItems: NSSet? //The Set that holds the many?
...
static func saveTimeSlot(timeSlot: TimeSlot) { //TimeSlot is the many object
retrieveValues()
var timeSlotArray = Array(self.timeSlotItems!)
timeSlotArray.append(timeSlot)
var setTimeSlotItems = Set(timeSlotArray)
self.timeSlotItems = setTimeSlotItems // This is the error line
}
Where retrieveValues() just updates all the coreData values in the class.
TimeSlot is the many object which I want to add.
I get an error on the last line, the error is: "cannot invoke initializer for type Set<_> with an argument of list of type Array"
Am I conceptually wrong at all? Thanks!
Nowadays it is this easy...
For a to-many item named say "Reply", CoreData knows to add a call "addToReplys".
Hence...
p = one Post. your core data Post items have many core data Reply items.
for jr in yourJson {
r = convert jr to a core data Reply
p.addToReplys( r )
so it's just
p.addToReplys( r )
Full example
For one-to-many this is easy. Just use the reverse to-one relationship.
timeSlot.item = self
For many-to-many I use this convenience method:
// Support adding to many-to-many relationships
extension NSManagedObject {
func addObject(value: NSManagedObject, forKey key: String) {
let items = self.mutableSetValueForKey(key)
items.addObject(value)
}
func removeObject(value: NSManagedObject, forKey key: String) {
let items = self.mutableSetValueForKey(key)
items.removeObject(value)
}
}
which is used like this:
self.addObject(slot, forKey:"timeSlotItems")
You've declared both timeSlotItems and saveTimeSlot: as static, so I'm not sure what your intention is there. I suspect it's not what you need.
In the same way that Core Data automatically runtime-generates optimized accessors for attributes, it also generates accessors for relations.
You don't say what the name of the "one" side of the to-many relation is, but if I assume that it's something like Schedule, where Schedule has a to-many relation to TimeSlot called timeSlotItems, then Core Data will runtime-generate the following accessors for you:
class Schedule: NSManagedObject {
#NSManaged public var timeSlotItems: Set<TimeSlot>
#NSManaged public func addTimeSlotItemsObject(value: TimeSlot)
#NSManaged public func removeTimeSlotItemsObject(value: TimeSlot)
#NSManaged public func addTimeSlotItems(values: Set<TimeSlot>)
#NSManaged public func removeTimeSlotItems(values: Set<TimeSlot>)
}

Realm query Object property field by its property

I'm developing an application for iOS using Swift and chose Realm as a database solution for it. I asked one question about Realm and now I have another.
Suppose we have a schema like this:
class Person: Object {
dynamic var id: String = NSUUID().UUIDString
dynamic var name: String?
dynamic var cars: Car?
class Car: Object {
dynamic var name: String?
I have one class (Person) that contains any number of objects of another class (Car). Car that are "linked" with the Person has some properties in context of that Person (and they can be different for same Car for different Persons or for two similar Cars for one Person). Using List<...>() we can not store such properties for each Item, am I right?
If we use Car only for one Person and only once we can create another class that includes only additional properties for Cars and links them with ID of Person plus ID of Car. But it does't work if we have two similar Cars with different additional properties.
So, how I see the solution. Have one table (class) stores ID of Person, ID of one Car and additional properties for this Car. For another Car for the same Person it has the same Person ID, Car ID (same or not) and another additional properties for this instance of a Car.
There is a problem (and a question that I mean). Having that structure I want to query all Cars from that table with their additional properties that have Person ID equals to some_id. How should I do this? Or maybe what another structure (maybe using List<...>) I should have to achieve such kind of behavior?
What is FastList exactly ?
If you want Items to have a property of Lists collection.
You have to redefine your Realm model. something like this.
class Car:Object{
dynamic var createDate: NSDate = NSDate()
}
class Person:Object{
let cars = List<Car>()
}
and query by predicate like this
let realm = Realm()
var ownedCarsFilterByDate = realm.objects(Person).filter("ANY cars.createDate = '\(date)'")
Edited to updated question
Your solution is to create table class, which has 'Person' , 'Car' and 'Context Attribute'.
Your model would be like this
class PersonAndCarRelation:Object{
dynamic var person: Person?
dynamic var car: Car?
dynamic var contextAttribute = ""
}
and you can query all cars associated with person
let personID = "123456789"
let personAndCarArray = realm.objects(PersonAndCarRelation).filter("person.id == \(personID)")
for personAndCar in personAndCarArray{
let personName = personAndCar.person.name
let carName = personAndCar.car.name
let context = personAndCar.contextAttribute
println("I am \(personName). I have a \(carName) with \(context)")
}

Resources