Core Data convert a superclass instance into a subclass instance? - iphone

What's the best way to programmatically convert an NSManagedObject-subclass (User) instance into an instance of its subclass (AccountUser)?
Setup
AccountUser inherits from User : NSManagedObject
When I sign up or log into the app for the first time, I become an AccountUser. Then, I download all of my friends and store them as User objects.
Both User & AccountUser have attributes firstName, lastName, etc. AccountUser has some extra things, like accessToken.
Problem
My friend John logs in on my device. Since he's my friend, he's already stored as a User. But now, I want to convert him into an AccountUser. What's the best way to do this programmatically? I have lots of attributes and relationships to preserve, so creating a new AccountUser object from a User object and then deleting the original User object is a lot to do. If I just create an AccountUser without deleting the User, things get messy. E.g. when I fetch User by ID, I get two objects back: one is the AccountUser, the other is the User.

One way to do it is to simply create a new AccountUser object and copy the relevant fields from the existing User object into it. Then deal with the old User object appropriately -- delete it, save it, whatever makes sense. It'd make sense to give AccountUser an initializer that takes an instance of User, like -initWithUser:.
Another (probably better) option would involve using a single class (User) for all users. If there's additional information to be stored for some users (currently AccountUsers), create a new Account class and associate an instance of Account with the users that require it. So the User objects that represent you and your friend John would each have associated Account objects, and all the other users wouldn't. When one of your other friends logs into your phone, you can create a new Account object for that person and associate it with their existing User object.

Maybe you can do it this way
Add the User entity a boolean property called "is_account_user".
Set a relationship between User and account user.
if a user has an account user, create the AcountUser entity and relate it to the User.
If the user has no account info then the "is_account_user" will be NO;
When you fetch for a user you can check if is_account_user is YES, and if so you can get his AcountUser with the relationship.
Hope it helps

Related

swift multiple user using core data

I have an app that ask user to login and then save username to core data and then go to task page to add new task with information using core data and tableview,
but my problem is I don't know how to make each user just see his tasks.I mean when I switch to another user he can add his own tasks without displaying other users tasks.I have done the login/registration and add tasks.
I'm new at developing apps,so any idea would be helpful.
This is a pretty broad question, but from a high-level standpoint you can establish a relationship (one-to-many) between a User entity and a Task entity so you can link each user to their tasks, and then when displaying tasks, use a query to fetch only those whose user relationship == the current user.

Use CloudKit to return users records and deny accounts

instead of code, have more of a best practice/functionality question regarding CloudKit. Can't seem to find answers, or maybe just don't understand.
Questions:
When I save the record, cloud kit creates a unique record id, i was thinking of getting that id and storing in core data to allow specific query's on that at a later time vs entire database searches. However, once I save a record, how do i get the record id that was created? Is this possible?
What if I allow a user to report another user for some reason and thereby want to block that user from posting to the cloud until a review can be done. Is there a user access database in the cloud? if not, thoughts on how to?
Thanks all.
By default when you create a CKRecord it will generate a guid as it's ID. You can also specify your own id the moment you create the CKRecord. The it does not need to be a guid. As long as it's unique. Your save action will have a callback where you will get the ID.
Every user has it's own unique id which you can easily get. You could create a table with your blocking information. You only have to query for that yourself to implement the blocking mechanism.

Friend list through relations

I'm creating a social media app. I'm able to allow the current user to search for a PFUser and add the user to a friendship relation. I'm struggling on accessing the friendship relation and getting all the friends to create a table view right now. Could someone help me with this?
A Relation type in Parse represents just like what it literal meaning is. It's just a relation that contains no data. If you want to access the data inside the relation. You will need to perform query on it like so:
let query = relation.query() // I assume relation is an instance of PFRelation you want
Actually, Parse tutorial provides us a very comprehensive guide and you should check that first: https://parse.com/docs/ios/guide#relations
NOTE: This answer provides alternatives to using Relations to make a Friend System
I have created a friend system in two ways using Parse and both a function of your specific needs.
The first time I implemented a friend system. I had a table of Users and a table of Relationships. The Relationships table stored the usernames (or ObjectIds) of the two users in a relationship and the state of that relationship (friends, request sent, etc). The problem with this is that the queries can be kinda complicated, and if you have a lot of users, this may end up being too slow.
The second option is storing friend information in the User table itself. For each user, you add the columns with they type Array: Friends, RequestSent, and RequestReceived. Anytime a user sends a request they update their own user row and send a message to CloudCode to update the other affected user. Take a look at this example:
User A sends a request to User B:
User A adds user B's name to RequestSent
User A sends a message to cloud code that he/she wants to add user B
CloudCode adds User A's name to User B's RequestReceived
User B wants to accept User A's request
User B adds user A's name to Friends
User B removes user A's name from RequestSent
User B sends a message to CloudCode that he/she wants to accept User A's friend Request
CloudCode adds user A's name to Friends
CloudCode removes user A's name from RequestReceived
With this option, you never perform any server side queries. You only ever perform get operations. The downside to this option is if the logged-in user has thousands of friends/requests, it will take a while to download that information.
Note: The reason you have to use CloudCode is that a User can only change information about him/herself. The other option is to have CloudCode manage all the adding/removing so better checks can be made.
I found with this method that you can sometimes have one user who is listed a a friend in another users row but not their own. Controlling everything from CloudCode could eliminate this kind of error.

ManagedObjectModel for my app

I read some articles and info in developer.apple.com about Core Data. Now I want to create ManagedObjectModel for my app. So I need to help - because it's first my planning about database. So my app will have next options
User must login with his Login and Password. So if he forget password, there is chance to create new pass by entering correct answer on secret question.
App will store contacts. Every contact have name, surname, photo, phones, and coollection of map annotations.
User can create some groups (like Family, Friends...)
So this app I create for understanding basics of objective-c and maybe there are no logic in my app.
Please check my entities, maybe I allowed blunder.
First entity Contact
id - number of contact.
image - I will store array there. So if image <200 Kb I insert it in database, if more I will save the path to this image
map - the dictionary of map annotations
name
phones - array of phone numbers
surname
Second entity Group
contacts - array that contain id of contacts, that belong to this group
id - number of group
title - it is the name of group (like Family, Friends...)
Third entity Login
groups - array that contain id of groups, that belong to this group
login
password
secret answer - answer to the secret question
secret question
Relationships
So each Login can have some groups, but each group will belong only to one Login. So I create "to-many relationship" for group relationship. So each group contain some contacts and contacts can be in some different gruops - I create many-to-many relationship.
About property "optional". I understand that if it's not check - this attribute or relationship have to be. So I remove this property for
"id" in Contact
"id" in Group
"login", "password" in Login
in relationship "toGroups" in Contact
in relationship "toLogin" in Group
About "Delete Rule". I want if I delete some Login all groups and contacts belong to this login must be delete. I can choose "Cascade" for relationship "group" in Login but it will delete only groups but not contacts. I cann't do such for relationship "toContact" because if I delete some Group it will delete contacts, but other Groups still can have this contacts. So maybe I must create attribute "contact" in Login that will be array of contacts, and create relationship to Contacts and if I delete Login all groups and contacts that belong to it, will be delete.
PS Sorry I am stil newbie and my question maybe funny for you, but I need help
A few things I noticed -
You have no need to use 'id' properties. Most databases plan on these for primary/foreign key management, but core data will manage this all for you provided you have the relationships set up. Also by this logic, you don't need properties to manually create that relationship (i.e. 'Contacts' in group and 'groups' in login
Are you sure you wants to be storing dictionaries and/or arrays in an entity? These sound like another standalone entity such as one for map annotations. Then you would build a one-to-many relationship from the original object to the new one.
Images stored as binary data are not the most efficient way to go about this. Its better to use the filesystem the app sandbox provides. Just saw a similar question the other day Storing images locally on an iOS device

Does Mongoid load the entire user object when the devise current_user variable is used?

I've embedded all the activities for a user and let's say most user has tens of thousands of activities associated with them. When checking the current_user in my controller code, does Mongoid load the entire user object containing all the embedded activity records? My gut feeling tells me no but I'd really want to confirm it so I can sleep better at night. :) Thank you!
Below is a short version of the User class.
class User
include Mongoid::Document
embeds_many :activities
end
EDIT
Let me clarify why I'm particularly interested to see if the entire object is loaded when using current_user. Since the activities are embedded in the user document, and most users have thousands of records, each full load would be expensive if all I want is just to check whether the user is signed in or not.
Yup. Devise requests the entire model when authenticating, so Mongoid will give you access to activities if you call current_user.activities.