How to access/modify parent view variable in subviews? - ios

I have parent view container which holds multiple subviews.
struct Person {
var name: String
var lastname: String
}
class ParentContainer: UIView {
var person = Person(name: "Vish", lastname: "Deshmukh")
let child1 = ChildView1(person)
let child2 = ChildView2(person)
let child3 = ChildView3(person)
}
How should I make sure if any of the child change person object, reflect that value everywhere including other child views and parent Container view?

This actually a fairly involved topic. If Person was a reference object, you could have your child views watch for changes to the Person. However, that's not really following best practices.
Modern design is moving to UDF (unidirectional data flow) where you have a value object that describes the current state of your UI and it gets passed around when it changes. With UDF, the child wouldn't change the person object - instead they would create a new, immutable person object containing changes, and notify subscribers that there is an updated person object. The children would be observing changes to the Person object.
The specifics depend on how you're implementing your app.

Related

Core Data with Different View Controllers

I'm still not getting some concepts in Core Data. Bear with me, my app begins with a ViewController that takes some inputs from the user. Once the user clicks on a UIButton, it will transform him to the next ViewController. This is not the case, the problem is that I created an object of the core data inside the UIButton's action outlet:
// Creating a new username & Saving it to Core Data
let newUser = UserInfo(context: self.context)
newUser.name = usersName.text
newUser.birthday = bdPicker.date
newUser.gender = genderTextField.text!
newUser.prevTested = yesOrNoTextField.text!
newUser.score = 0
I declared the context as a global in the First ViewController:
var info:[UserInfo]?
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
Now, in the all the remaining ViewControllers, I need to modify the newUser.score entity. Since the app is question-and-answer, I need to modify the score each time I display a question to the user in each view controller. I tried so many solutions, but did not work. I've been told I should create newUser as a Property instead of a local variable. How is this possible?
One option could be to use the Singleton Pattern. Essentially, you create a new class, and create a static variable (by convention, often named shared) that's initialized to an instance of the class. Add a newUser property to this class, and then you can view or modify its state across all your ViewControllers.
class Singleton{
var shared = Singleton()
//Declare your newUser here
}
Additionally, if you are using CoreData in your application, I highly reccomend ommiting the use of the global variable for the context, and the placement of your CoreData save logic inside of the ViewController class. Instead, write another class, such as CoreDataManager or CoreDataService (You can call it whatever you'd like) and declare context as a property of that class so that it can be used in your create, fetch, and save operations.

Treat LinkingObjects as List

I have a model which references all object with a reference to itself. I thought I could use this property, LinkingObjects(fromType: Outfit.self, property: "clothes") as a List<Outfit> and just patch it right into my existing code.
Specifically I need to use the observe function of List. Is there any way to treat LinkingObjects equally as List?
Let me give this a shot with an example - you may be approaching it backwards or I may not fully understand the question.
Suppose you have an Outfit class that has a List property of clothing objects
OutfitClass: Object {
let clothingObjects = List<ClothingClass>
}
and then a class that holds each clothing type with a Link back to a particular OutfitClass. Now we have an inverse relationship.
ClothingClass: Object {
#objc dynamic var description = ""
let outfits = LinkingObjects(fromType: OutfitClass.self, property: "clothingObjects")
}
So each outfit has a list of clothes, jacket, button up shirt, tie etc and each of those items would know what outfit or outfits it belongs to.
That should satisfy the requirements where a model (the ClothingClass)
which references all objects (the OutfitClass) with reference to itself
I understand the objective is that you want to add an observer to all Outfit objects where a certain clothing item is referenced. So for example: the Red Tie Clothing Class object wants to observe all Outfits that reference that Red Tie.
So the approach is like this
First, we need to load in the Clothing Class object we are interested in
let redTieResults = realm.objects(ClothingClass.self).filter("descripton == 'Red Tie'")
no error checking here but let's assume that Red Tie is guaranteed to exist
let thisRedTie = redTieResults.first!
Now lets get the results, to which we can add an observer, for any Outfit class objects that have this specific Red Tie object in their List
let outfitResults = realm.objects(OutfitClass.self).filter("ANY clothingObjects == %#", thisRedTie)
then you add an observer to the outfitResults

How to delete an object based on a specific property that is nil

I have three models, a parent, child, grandchild. I have been able to save and link the data correctly. Now I would like to be able to delete the child and grandchild objects, when I delete the parent.
The parent has a property of the child and the child has a property of the grandchild.
Example:
class Parent: Object {
dynamic var name = ""
var child = List<Child>
}
class Child: Object {
dynamic var name = ""
dynamic var parent: Parent?
var grandChild = List<GrandChild>
}
class GrandChild: Object {
dynamic var name = ""
dynamic var child: Child?
}
(This is not my actual code, so if I messed up on anything here please disregard any errors.)
What I would like to do is to delete the parent, which would make the property of 'parent' in the Child object nil. Then I would like to delete the child object if it's parent property is nil. Then do the same for the grandChild. In other words do a cascading deletion of objects.
So, something like:
if the parent property of Object: Child is nil, then delete the Object.
This seems like a simple problem to solve but I can't find a lot of examples of nested data models from Realm on these boards, or I am not asking the questions in the right way to find them.
There is no support for cascading deletes in Realm currently, so you have to manually remove child instances. You can use LinkingObjects to remove all children before deleting the parent or just query all child instances where parent == nil after parent is deleted and delete them. See more possible solutions here: https://github.com/realm/realm-cocoa/issues/1186

Class or Struct for a model similar to a relational database?

The application in question is built as follows:
A user selects a job
the job can have many components
each component can have many lineitems.
I am not clear on how this should be structured - should this be class or structs? Seeing that only one job is being processed at a time, I am fairly confident that jobs should be a class. However, when there are multiples of a certain object type, I am not exactly clear on how to form them, like the components and lineitem objects.
The application consists of ViewControllers and TableViewControllers. All the data is fetched from a server in JSON and populated into the appropriate view as needed. Here are the object types as they are currently setup:
A job object:
// Job Object
//
public struct Job {
static var globalId : String?
static var name : String?
static var status : String?
static var client = Client()
static var components = Array<Component>()
// etc..
}
A Component like so:
// JobComponent Object
//
public struct Component {
var name:String? = ""
var fmRecordId : String?
var startTS:NSDate?
var endTS:NSDate?
var notes:String? = ""
var items = Array<Lineitem>()
// etc...
}
and finally, a lineitem:
// Lineitem Object
//
public struct Lineitem {
var fmRecordId = String()
var itemName = String()
var itemNumber = String()
// etc...
}
All of these object are built within a public class called "PL".
When a user selects lineitem and edits it's values, the values are not available outside the VC in which they are edited because the VC isn't referencing the lineitem that is was passed, it is simply copying it. The same happens with components.
A workaround I found was to use the the Job struct PL.Job.self and always modify the components and lineitems like so where i = a desired index in the array:
PL.Job.components[i] to access a component
PL.Job.components[i].items[i] to access a specific item within that component.
However, this doesn't scale very well.
The desired behavior is to be able to pass a reference to a particular instance of an object around rather than pass around the index path of those objects in the PL.Job object.
I am well aware there is something wrong with how this is currently structured, but could someone please point me in the right direction?
A couple of points:
You can only pass class instances by reference. If you want to be able to pass a reference to a particular LineItem or Component or Job, and you want to be able to make changes to that object that are effective everywhere, then you need to define them as classes and not structs. Instances of struct types are always passed by value and not be reference. And when a value type is passed, it is copied, meaning that you create an entirely new copy of the object, and mutating the copy has no effect on the original.
Your Job struct only has static properties - i.e., there will only ever be one globalId, name, status etc. throughout your entire application. If you want to have multiple instances of Job, then these should not be static properties. You say that only one Job will be processed at a time, so maybe that was intentional. Either way, it is still often preferable to create an instance of a Job class that has those properties. It certainly would give you more flexibility later if you decide to make it possible to hold references to multiple jobs in memory, or to allow the user to select between different jobs, or switch between jobs, etc. For example, you may want to allow a user to switch to the Job they were processing earlier without necessarily destroying the Job that they are working on now.
But I think the main point is that you will need to define your objects as classes if you want to be able to pass them by reference. If you modify an object that is passed by reference, all other references to the same object will show the same changes (because, after all, they are just references to the same object). That doesn't work with value types, like structs.

breezejs - How to initiate complex type properties when creating a new Entity

Suppose there is person type which has some complex properties such as Address and dateOfBirth
I created a new Entity of person with this code :
newPerson(manager.createEntity("Person",{ id: breeze.core.getUuid() }));
How can I initiate the complex type so I can bind it to a blank form?
In the breeze doc it says :http://www.breezejs.com/documentation/complextype-properties
This is actually slightly incorrect, you can create an ‘unbound’
instance of a complexType with the complexType.createInstance method
but when you assign it, you are simply copying its values onto an
existing instance.
Where is the best place to initiate the complex type properties?any sample code would be so helpful.
If you are dealing with a scalar navigation property, i.e. a navigation property that returns a single instance of another entity, then you can do it right in the createEntity call
newDetail = manager.createEntity("OrderDetail", { Order: parentOrder, Product: parentProduct });
If you are dealing with a nonscalar (i.e. array) navigation property then you will need to push the children into the navigation property. i.e.
newCustomer = em.createEntity("Customer");
var orders = newCustomer.getProperty("Orders");
orders.push(order1);
orders.push(order2);
// OR
// orders.push.apply(orders, ordersToPush);

Resources