Help!!!I have a one-to-many relationship.
Why does [self.menu addSubMenuObject:newSubMenu] not work?
ManagerCoreData * managerCoreData = (ManagerCoreData *)[ManagerCoreData sharedInstance];
NSManagedObjectContext * managedObjectContex = managerCoreData.managedObjectContext;
SubMenu * newSubMenu =(SubMenu*) [NSEntityDescription insertNewObjectForEntityForName:#"SubMenu" inManagedObjectContext:managedObjectContex];
[self.menu addSubMenuObject:newSubMenu];
if (newSubMenu != nil){
newSubMenu.name = self.textFieldName.text;
newSubMenu.cost = [NSNumber numberWithInteger:[self.textFieldCost.text integerValue]];
newSubMenu.about = self.textFieldAbout.text;
newSubMenu.imageOriginal = self.imageView.image;
NSError * savingError = nil;
if ([managedObjectContex save:&savingError]){
[self.navigationController popViewControllerAnimated:YES];
}else {
NSLog(#"Failed to save manager object contex!!!Error %#",savingError);
}
}else {
NSLog(#"Failed to create new object!!!");
}
#class SubMenu;
#interface Menu : NSManagedObject
#property (nonatomic, retain) NSData * imageMiddle;
#property (nonatomic, retain) id imageOriginal;
#property (nonatomic, retain) NSData * imageSmall;
#property (nonatomic, retain) NSString * name;
#property (nonatomic, retain) NSSet *subMenu;
#end
#interface Menu (CoreDataGeneratedAccessors)
- (void)addSubMenuObject:(SubMenu *)value;
- (void)removeSubMenuObject:(SubMenu *)value;
- (void)addSubMenu:(NSSet *)values;
- (void)removeSubMenu:(NSSet *)values;
#end
* Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[SubMenu menu]: unrecognized selector sent to instance 0x74caf90'
Related
I have a singleton class which I intend to share throughout my whole application.
It looks like this:
.m
#implementation PersonalGlobal
#synthesize firstName;
#synthesize lastName;
#synthesize SSN;
#synthesize customerNo;
#synthesize email;
#synthesize address;
#synthesize city;
#synthesize postalCode;
#synthesize telNo;
#synthesize mobileNo;
#pragma mark Singleton Methods
+ (id)sharedPersonal {
static PersonalGlobal *sharedPersonalGlobal = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedPersonalGlobal = [[self alloc] init];
});
return sharedPersonalGlobal;
}
- (void)dealloc {
[super dealloc];
// Should never be called
}
#end
.h
#import <foundation/Foundation.h>
#interface PersonalGlobal : NSObject {
NSString *firstName;
NSString *lastName;
NSString *SSN;
NSString *customerNo;
NSString *email;
NSString *address;
NSString *city;
NSString *postalCode;
NSString *telNo;
NSString *mobileNo;
}
#property (nonatomic, retain) NSString *firstName;
#property (nonatomic, retain) NSString *lastName;
#property (nonatomic, retain) NSString *SSN;
#property (nonatomic, retain) NSString *customerNo;
#property (nonatomic, retain) NSString *email;
#property (nonatomic, retain) NSString *address;
#property (nonatomic, retain) NSString *city;
#property (nonatomic, retain) NSString *postalCode;
#property (nonatomic, retain) NSString *telNo;
#property (nonatomic, retain) NSString *mobileNo;
+ (id)sharedPersonal;
#end
In the code I save strings to it like so:
PersonalGlobal *sharedPersonal = [PersonalGlobal sharedPersonal];
sharedPersonal.firstName = #"Some string";
But when I change view and try to access the string like this:
PersonalGlobal *sharedPersonal = [PersonalGlobal sharedPersonal];
//Setting some textfield
sometextfield.text = sharedPersonal.firstName;
I get nothing. I have done a #import "PersonalGlobal.h" in all the files.
Can i commit the changes in any way to the singleton class?
Can anyone see what I am doing wrong here?
Thanks!
Your implementation is looking fine. This should work if your singleton returning the only one instance . So the point of doubt in your sharedPersonal method . Just try to add breakpoints in this method and see whether it is creating a new instance every time .for the reference I got this SO question.
If not then you can also try this :
+(SingleTon *)getSharedInstance
{
static PersonalGlobal *sharedPersonalGlobal = nil;
if (sharedPersonalGlobal==nil)
{
sharedPersonalGlobal=[[PersonalGlobal alloc]init];
}
return sharedPersonalGlobal;
}
This is working code for me.
Your singleton implementation looks ok. I wouldn't be surprised if in this case the code that you wrote to set the firstName just never gets executed. If I were you I would step through the codes.
I'm quite new to Objective-C. I've been trying to fetch from my core data entity. The following code fetches the right row because it only returns 1 result.
but when I try to NSlog() it to see its values what I get is:
iGym[3922:c07] (
"<User: 0x8397690> (entity: User; id: 0x8341580 <x-coredata://114815EF-85F4-411F-925B-8479E1A94770/User/p19> ; data: <fault>)"
)
I am used to PHP that I just do a var_dump() and i get all the information in the array... specially when I am expecting 16 results as this entity has 16 fields.
Could anyone tell me how could I inspect that array?
and also, most important, how do I ultimately do this: fetch the Gender field of the matched email field and assign it to a NSString variable.
The query i want to do in sql is SELECT Gender FROM myTable WHERE email = "something#something.com;
-(NSInteger*)selectedGenderMethod
{
NSEntityDescription *entityDesc = [NSEntityDescription entityForName:#"User" inManagedObjectContext:context];
NSFetchRequest *request = [[NSFetchRequest alloc] init];
[request setEntity:entityDesc];
request.predicate = [NSPredicate predicateWithFormat:#"email = %#",_currentUser];
NSError *error = nil;
NSArray *matches = [[context executeFetchRequest:request error:&error] mutableCopy];
NSString * someVar= [matches[0] objectForKey:#"email"];
NSLog(#"%#",someVar);
//More to come once this is sorted
return 0;
}
This fetching code is happening in my genderPickerViewController : UIViewController
NSLog(#"%#", matches[0]);
returns
<User: 0x83a6b00> (entity: User; id: 0x83995f0 <x-coredata://114815EF-85F4-411F-925B-8479E1A94770/User/p19> ; data: <fault>)
This is my User.h:
#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>
#interface User : NSManagedObject
#property (nonatomic, retain) NSDate * dob;
#property (nonatomic, retain) NSString * email;
#property (nonatomic, retain) NSNumber * firstTime;
#property (nonatomic, retain) NSString * gender;
#property (nonatomic, retain) NSString * height;
#property (nonatomic, retain) NSNumber * idFB;
#property (nonatomic, retain) NSNumber * idUserExternal;
#property (nonatomic, retain) NSNumber * idUserInternal;
#property (nonatomic, retain) NSNumber * isPT;
#property (nonatomic, retain) NSString * language;
#property (nonatomic, retain) NSString * metricSystem;
#property (nonatomic, retain) NSString * name;
#property (nonatomic, retain) NSString * nickname;
#property (nonatomic, retain) NSString * password;
#property (nonatomic, retain) NSString * surname;
#property (nonatomic, retain) NSString * weight;
#end
User.m:
#implementation User
#dynamic dob;
#dynamic email;
#dynamic firstTime;
#dynamic gender;
#dynamic height;
#dynamic idFB;
#dynamic idUserExternal;
#dynamic idUserInternal;
#dynamic isPT;
#dynamic language;
#dynamic metricSystem;
#dynamic name;
#dynamic nickname;
#dynamic password;
#dynamic surname;
#dynamic weight;
#end
Is the user object a NSDictionary or an NSArray by chance? If that is the case you are simply logging out the object, you will need to specify a specific entity in the object to output.
For example if it's a NSDictionary
NSString *name = [matches[0] objectForKey:#"name"];
NSLog("Name %#", name);
You could also try
NSString *email = (User *)matches[0].email;
NSLog("Email %#", email);
What you are doing is right, you usually get the full objects and not only one attribute, Core Data is an object storage.
So you only need [((User *)matches[0]) gender] to get the gender of the returned user.
If you want to get some extra information from objects you must implement:
- (NSString *)description
It is used for converting to string and logging.
You can use the following code,
[NSPredicate predicateWithFormat:#"email CONTAINS[c] %#", _currentUser];
OR
[NSPredicate predicateWithFormat:#"email CONTAINS[cd] %#", _currentUser];
then you can print the fetched results as type po OBJECT_NAME.PROPERTY in debug area
i have two NSManagedObject classes, UserInfo and Department (to-one and to-many relationship respectively )here is my code,
// UserInfo.h
#interface UserInfo : NSManagedObject
#property (nonatomic, retain) NSDate * bDate;
#property (nonatomic, retain) NSString * firstName;
#property (nonatomic, retain) NSString * lastName;
#property (nonatomic, retain) NSString * userName;
#property (nonatomic, retain) Department *dept;
#end
//Department.h
#class UserInfo;
#interface Department : NSManagedObject
#property (nonatomic, retain) NSString * id;
#property (nonatomic, retain) NSString * post;
#property (nonatomic, retain) NSString * location;
#property (nonatomic, retain) NSString * name;
#property (nonatomic, retain) NSSet *user;
#end
#interface Department (CoreDataGeneratedAccessors)
- (void)addUserObject:(UserInfo *)value;
- (void)removeUserObject:(UserInfo *)value;
- (void)addUser:(NSSet *)values;
- (void)removeUser:(NSSet *)values;
#end
for searching particular user from db i used, which works well
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"firstName contains[cd] %#", NameTosearch];
but, now what kind of predicate i can use to fetch all users with info connected to particular department?
You can also use a comparison with an object in predicates.
I.e. If you have a pointer to a Department instance in dept:
...withFormat:#"dept = %#", dept"
internally CoreData will replace the %# with the managed object identifier of the object.
Search using
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"firstName contains[cd] == %#", NameTosearch];
Follow this blog for more info http://rajneesh071.blogspot.in/
And follow my answer StackOverflow
When I do Analyze to find out the potential memory leak, I get a "Incorrect decrement of the reference count of an object that is not owned at this point by the caller" :
- (int)downloadUrlTofolder:(NSString *)url filename:(NSString *)name tryTime:(int)tryTime
{
int result = 0;
GetFtpService *ftpService = [[GetFtpService alloc] initwithUrlandOutPut:url output:name];
//I have delete the code here, but problem is not solved.
[ftpService release]; //the potential problem point to this line
return result;
}
Below is the "initwithUrlandOutPut" method:
- (id)initwithUrlandOutPut:(NSString *)url output:(NSString *)o
{
if(self = [super init]) {
self.urlInput = url;
self.outPath = o;
self.success = [NSString stringWithString:#"success"];
self.connected = nil;
}
return self;
}
And the interface:
#interface GetFtpService : NSObject <NSStreamDelegate>
#property (nonatomic, retain) NSInputStream *networkStream;
#property (nonatomic, copy) NSString *urlInput;
#property (nonatomic, retain) NSInputStream *fileStream;
#property (nonatomic, copy) NSString *outPath;
#property int tryTime;
#property (nonatomic, copy) NSString *success;
#property (nonatomic, copy) NSString *connected;
- (id) initwithUrlandOutPut:(NSString *)url output:(NSString *)o;
I want to know why this happened? and how to fix it?
I suspect it's because the 'w' in "initwith..." is not capitalized. Maybe the analyzer is not recognizing the method as an init method because of that.
I have to main issues that I believe are related as they both occur on the same line of code.
Data Model
NB: I have simplified the code and model as best I can.
I have 3 entities in my Core data model.
Merchant (can have many Branches, can have many Sectors)
Sector (can have many Merchants)
Branch (can have one Merchant)
Data is downloaded (in JSON) to the app. Each Merchant is iterated over sectors are extracted, if the sector exists it is fetched and added to a NSMutableArray.
...
//Iterating through Merchants
...
for(NSDictionary *sector in sectors) {
NSLog(#"\tfetch sectors ID %#", [sector objectForKey:#"sector_id"]);
NSPredicate *sectorPredicate = [NSPredicate predicateWithFormat:#"%K == %d", #"sectorID", [[sector objectForKey:#"sector_id"] integerValue]];
[sectorRequest setPredicate:sectorPredicate];
NSArray *existingSector = [self.managedObjectContext executeFetchRequest:sectorRequest error:&error];
if(!error && [existingSector count] == 1) {
NSLog(#"\tfound sector");
[merchantSectors addObject:[existingSector objectAtIndex:0]];
}
else {
NSLog(#"\tcreate a new sector");
//Create a new sector
Sector *newSector = [[Sector alloc] initWithEntity:sectorEntity insertIntoManagedObjectContext:self.managedObjectContext];
newSector.sectorID = [NSNumber numberWithInteger:[[sector objectForKey:#"sector_id"] integerValue]];
newSector.name = [sector objectForKey:#"name"];
[merchantSectors addObject:newSector];
[newSector release]; newSector = nil;
}
}
[sectorRequest release]; sectorRequest = nil;
NSLog(#"\tadd sectors to merchant");
[currentMerchant addSector:merchantSectors]; //<---- crash and hang
The App will either hang at:
[currentMerchant addSector:merchantSectors];
or sometimes throw an exception:
*** Terminating app due to uncaught exception \
'NSInternalInconsistencyException', reason: \
'-[__NSCFSet addObject:]: mutating method sent to immutable object'
The Branch parsing code is almost identical but never has these issues or the app will hang or crash before it becomes an issue (??).
If the App is deleted and reinstalled the code will work fine, is it possible that existing identical relationships are causing this problem?
Edit: The parsing of the JSON is called using an NSInvocationOperation, so when it hangs the interface stays responsive. The crash version kills the app.
Edit 2: Merchant.h and Merchant.m
Merchant.h
#import <CoreData/CoreData.h>
#class Branch;
#class Sector;
#interface Merchant : NSManagedObject
{
}
#property (nonatomic, retain) NSString * street;
#property (nonatomic, retain) NSString * locality;
#property (nonatomic, retain) NSString * city;
#property (nonatomic, retain) NSNumber * merchantID;
#property (nonatomic, retain) NSString * postcode;
#property (nonatomic, retain) NSString * property;
#property (nonatomic, retain) NSString * organisation;
#property (nonatomic, retain) NSDate * expires;
#property (nonatomic, retain) NSSet * Branch;
#property (nonatomic, retain) NSSet* Sector;
#end
#interface Merchant (CoreDataGeneratedAccessors)
- (void)addBranchObject:(Branch *)value;
- (void)removeBranchObject:(Branch *)value;
- (void)addBranch:(NSSet *)value;
- (void)removeBranch:(NSSet *)value;
- (void)addSectorObject:(Sector *)value;
- (void)removeSectorObject:(Sector *)value;
- (void)addSector:(NSSet *)value;
- (void)removeSector:(NSSet *)value;
#end
Merchant.m
#import "Merchant.h"
#import "Branch.h"
#implementation Merchant
#dynamic street;
#dynamic locality;
#dynamic city;
#dynamic merchantID;
#dynamic postcode;
#dynamic property;
#dynamic organisation;
#dynamic expires;
#dynamic Branch;
#dynamic Sector;
#end
Try to add Sectors to Merchant one by one using CoreData add<Key>Object: and remove<Key>Object: auto-generated methods (as described in Custom To-Many Relationship Accessor Methods)
for(NSDictionary *sector in sectors) {
NSPredicate *sectorPredicate = [NSPredicate predicateWithFormat:#"%K == %d", #"sectorID", [[sector objectForKey:#"sector_id"] integerValue]];
[sectorRequest setPredicate:sectorPredicate];
NSArray *existingSector = [self.managedObjectContext executeFetchRequest:sectorRequest error:&error];
if(!error && [existingSector count] == 1)
{
[currentMerchant addSectorObject:[existingSector lastObject]];
}
else
{
Sector *newSector = [[Sector alloc] initWithEntity:sectorEntity insertIntoManagedObjectContext:self.managedObjectContext];
newSector.sectorID = [NSNumber numberWithInteger:[[sector objectForKey:#"sector_id"] integerValue]];
newSector.name = [sector objectForKey:#"name"];
[currentMerchant addSectorObject:newSector];
[newSector release];
}
}
Or you can retrieve mutable proxy object contains currentMerchants's sectors via mutableSetValueForKey: and add sectors to it:
NSMutableSet *merchantSectors = [currentMerchant mutableSetValueForKey:#"sector"];
for(NSDictionary *sector in sectors) {
NSPredicate *sectorPredicate = [NSPredicate predicateWithFormat:#"%K == %d", #"sectorID", [[sector objectForKey:#"sector_id"] integerValue]];
[sectorRequest setPredicate:sectorPredicate];
NSArray *existingSector = [self.managedObjectContext executeFetchRequest:sectorRequest error:&error];
if(!error && [existingSector count] == 1)
{
[merchantSectors addObject:[existingSector lastObject]];
}
else
{
Sector *newSector = [[Sector alloc] initWithEntity:sectorEntity insertIntoManagedObjectContext:self.managedObjectContext];
newSector.sectorID = [NSNumber numberWithInteger:[[sector objectForKey:#"sector_id"] integerValue]];
newSector.name = [sector objectForKey:#"name"];
[merchantSectors addObject:newSector];
[newSector release];
}
}
Anyway, for convenience it's better to use lowercase sectors name for Mecrhant entity for to-many relationship with Sector entity: lowercase not to be ambiguous with Sector class name, and with s at and to be sure, that getter methods for this property return multiple objects.