So here's the deal: I have a custom UIViewController named FieldFormVC. In order to present it, I call this code:
FieldFormVC *fieldFormVC = [[FieldFormVC alloc] initWithFieldForm:(FieldForm *)[self getForm] andManagedObjectContext: managedObjectContext];
fieldFormVC.trackManager = self;
fieldFormVC.thisTrackNumber = currentScreenIndex;
fieldFormVC.textSize = textSize;
[navigationController pushViewController:fieldFormVC animated:YES];
Where [self getForm] returns a FieldForm object. The code for the initWithFieldForm: andManagedObjectContext: method is:
-(id)initWithFieldForm: (FieldForm *) f andManagedObjectContext: (NSManagedObjectContext *) moc
{
if (self = [super init])
{
fieldForm = f;
managedObjectContext = moc;
}
return self;
}
I set up some breakpoints, and when the initWithFieldForm: andManagedObjectContext: is called, the parameters "f" and "moc" contain actual values. At the end of the method, fieldFormVC has all the values it needs.
Now when it goes back to the first chunk of code and calls
fieldFormVC.trackManager = self;
All the values in fieldFormVC go to 0x00000000. All the properties of the fieldFormVC are set with #property (nonatomic, retain) and they are #synthesize'd as well.
The strange thing is that I have used similar initWith.. methods that have turned out great, and I've never seen this issue before. If it helps, I am using Core Data in my project, and FieldForm is a certain entity in my model. Thanks for any advice and help!
Update:
The getForm method's code:
-(NSObject *) getForm
{
WrapperForm *wrapperForm = (WrapperForm *)[[_fetchedResultsController fetchedObjects]objectAtIndex:currentScreenIndex.intValue];
FieldForm *fieldForm = wrapperForm.fieldForm;
PictureForm *pictureForm = wrapperForm.pictureForm;
if (fieldForm != nil)
{
NSLog(#"Class: %#", [wrapperForm.fieldForm.class description]);
return fieldForm;
}else if(pictureForm != nil)
{
NSLog(#"Class: %#", [wrapperForm.pictureForm.class description]);
return pictureForm;
}
return nil;
}
You are casting to FieldForm although your method getForm should actually return a FieldForm class anyway. Most likely the getForm method does not return the correct object.
Related
I have a moc (self.managedObjectContext) which was created with NSMainQueueConcurrencyType.
Now, for a method invoked this way -
ManagedObjectType1 *obj1 = [self createAnObject];
With the implementation for createAnObject being -
- (ManagedObjectType1 *) createAnObject {
NSManagedObjectContext *childContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
childContext.parentContext = self.managedObjectContext;
ManagedObjectType1 *obj1 = //..initialize in childContext
return obj1
}
obj1 is nil after the method returns (at the place where it was invoked) and yet obj1 has data in the method implementation at the time of being returned.
What could be going wrong here. I have tried assigning childContext with NSPrivateQueueConcurrencyType but that hasn't helped either.
This worked. But is this a good way to do it.
- (ManagedObjectType1 *) createAnObject {
__block ManagedObjectType1 *obj1;
[self.managedObjectContext performBlockAndWait:^{
NSManagedObjectContext *childContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
childContext.parentContext = self.managedObjectContext;
obj1 = //..initialize in childContext
}];
return obj1
}
how does my fetchedResultsController method look like, if I want to fetch all my attributes for an entity from core data? I only know and understand how to fetch data for a tableView and I think that is where all my confusion is coming from.
Here is my Core-Data setup:
I'm trying to fill an array with all the Attributes my Setting entity has and the show those values via NSLog output in my debug console.
Here is what I changed so far:
AppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
NSManagedObjectContext *context = [appDelegate managedObjectContext];
NSManagedObject *newEntry = [NSEntityDescription insertNewObjectForEntityForName:#"Setting" inManagedObjectContext:context];
//NSManagedObject *newSetting = [NSEntityDescription insertNewObjectForEntityForName:#"Setting" inManagedObjectContext:context];
[newEntry setValue: #"StudiSoft" forKey:#"settingName"];
if (_overrideSysTimeSwitch.on) {
[newEntry setValue: #YES forKey:#"settingSysTimeOverride"];
//editSetting.settingSysTimeOverride = #YES;
NSLog(#"IF A");
} else {
//[newEntry setValue: #NO forKey:#"settingSysTimeOverride"];
//editSetting.settingSysTimeOverride = #NO;
NSLog(#"IF B");
}
if (_timeFormatSwitch.on) {
//[newEntry setValue: #YES forKey:#"settingTimeFormat"];
//editSetting.settingTimeFormat = #YES;
NSLog(#"IF C");
} else {
//[newEntry setValue: #NO forKey:#"settingTimeFormat"];
//editSetting.settingTimeFormat = #NO;
NSLog(#"IF D");
}
[self.settingsArray addObject:#"StudiSoft"];
NSError *error;
[context save:&error];
I'm using this code-snipped that and I'm able to modify the core data content.
However, every time I run this code, it of course adds a new object.
I've been looking for a way to update existing Attributes in my Entity, or modify them, but I could NOT find them.
Anyhow this is a good step into the right direction.
I created a completely new project, with just one view, once I have it working on the main view I'm going to experiment with segues....
But for now, how would I update or change existing attributes?
Thanks guys!!
This is my editSave Method to store some data in core data:
- (IBAction)editSave:(UIBarButtonItem *)sender
{
if ([_editSaveButton.title isEqualToString:#"Edit"])
{
[self setTitle:#"Edit Settings"];
//self.title = #"Edit Settings";
_overrideSysTimeSwitch.userInteractionEnabled = YES;
_timeFormatSwitch.userInteractionEnabled = YES;
_editSaveButton.title = #"Save";
} else if ([_editSaveButton.title isEqualToString:#"Save"])
{
[self setTitle:#"Settings"];
//self.title = #"Settings";
_overrideSysTimeSwitch.userInteractionEnabled = NO;
_timeFormatSwitch.userInteractionEnabled = NO;
_editSaveButton.title = #"Edit";
// #############################################################
AppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
NSManagedObjectContext *context = [appDelegate managedObjectContext];
//NSManagedObject *newEntry = [NSEntityDescription insertNewObjectForEntityForName:#"Setting" inManagedObjectContext:context];
//[newEntry setValue: #"StudiSoft" forKey:#"settingName"];
/*NSString *firstName = [anEmployee firstName];
Employee *manager = anEmployee.manager;
Setting *newSetting = [NSString #"Test"];
[newSetting setValue:#"Stig" forKey:#"settingName"];
[aDepartment setValue:[NSNumber numberWithInteger:100000] forKeyPath:#"manager.salary"];*/
//editSetting.settingName = #"Test";
if (_overrideSysTimeSwitch.on) {
//[newEntry setValue: #YES forKey:#"settingSysTimeOverride"];
editSetting.settingSysTimeOverride = #YES;
NSLog(#"IF A");
} else {
//[newEntry setValue: #NO forKey:#"settingSysTimeOverride"];
editSetting.settingSysTimeOverride = #NO;
NSLog(#"IF B");
}
if (_timeFormatSwitch.on) {
//[newEntry setValue: #YES forKey:#"settingTimeFormat"];
editSetting.settingTimeFormat = #YES;
NSLog(#"IF C");
} else {
//[newEntry setValue: #NO forKey:#"settingTimeFormat"];
editSetting.settingTimeFormat = #NO;
NSLog(#"IF D");
}
//[self.settingsArray addObject:#"StudiSoft"];
NSError *error = nil;
//if ([self.managedObjectContext hasChanges]) {
//NSLog(#"SAVE & DISMISS conetx has changed");
if (![context save:&error]) { // save failed
NSLog(#"Save failed: %#", [error localizedDescription]);
} else { // save succeeded
NSLog(#"Save Succeeded");
}
//}
//[self.tableView reloadData];
// #############################################################
}
}
Debug Output:
2014-06-10 19:09:29.881 SettingsCoreData[508:60b] Entry #5: <Setting: 0x8f983e0> (entity: Setting; id: 0x8f97030 <x-coredata://FA78AB86-3225-4B1E-97DD-3F31F5323A18/Setting/p6> ; data: {
settingName = StudiSoft;
settingSysTimeOverride = 0;
settingTimeFormat = 0;
})
2014-06-10 19:09:29.883 SettingsCoreData[508:60b] Entry #6: <Setting: 0x8f98430> (entity: Setting; id: 0x8f97040 <x-coredata://FA78AB86-3225-4B1E-97DD-3F31F5323A18/Setting/p7> ; data: {
settingName = StudiSoft;
settingSysTimeOverride = 1;
settingTimeFormat = 1;
})
Now I should be able to use something like this in my viewDidLoad, right?
if (editSetting.settingSysTimeOverride.boolValue == 0) {
_overrideSysTimeSwitch.on = NO;
} else {
_overrideSysTimeSwitch.on = YES;
}
But it doesn't work as I thought it will :-(
Next you need to call -performFetch: on the NSFetchedResultsController. Make sure you check the response and handle the error if the response is NO.
From there your NSFetchedResultsController is populated and ready to be used. You can then grab individual elements via -objectAtIndex: or you can grab them all with -fetchedObjects.
I would suggest just reviewing the documentation on the methods that are available as it has pretty strong and clear documentation.
Update
If you are not receiving any data then break it down. Take the NSFetchRequest that you created and call -executeFetchRequest:error: against your NSManagedObjectContext and see if you get any data back.
If you do then there is something wrong with your handling of the NSFetchedResultsController.
If you don't then there is something wrong with your NSFetchRequest or you don't have any data in your store.
Update
Sounds like you need to read a book on how Core Data works.
A NSFetchRequest is a query against Core Data so that objects can be returned from the store. You can pass a NSFetchRequest to a NSFetchedResultsController so that the NSFetchedResultsController can monitor the store for changes and let your view controller know when those changes occur.
A NSFetchRequest can also be executed directly against the NSManagedObjectContext and you can retrieve the results directly. You do that by calling -executeFetchRequest:error: against your NSManagedObjectContext and getting a NSArray back. You can then check that NSArray to see if you get any results.
If you do not understand that paragraph then you need to take a step back and read the tutorials on Core Data and/or read a book on Core Data. I can recommend an excellent book on the subject ;-)
I want to know the porper way to create the singleton class.Currently I am doing in the following way.
In the .h file I am declaring the instance of the class in the following way.
#interface GlobalMethods : NSObject
{
}
+ (GlobalMethods *)sharedInstance;
And in the .m file I did the code in the following way.
#implementation GlobalMethods
- (id)init
{
self = [super init];
if (self)
{
//Custom Intialization
}
return self;
}
+ (GlobalMethods *)sharedInstance
{
static GlobalMethods *sharedInstance = nil;
#synchronized(self)
{
if (sharedInstance == NULL)
{
sharedInstance = [[GlobalMethods alloc] init];
}
return sharedInstance;
}
}
we can create only one instance from that singleton class. take a
look at this page for more information with code :
http://www.galloway.me.uk/tutorials/singleton-classes/
I'm using in-memory NSPersistentStores to hold transient objects. Once the store is unused - which doesn't necessarily mean empty - I'd like to remove it from the coordinator to free up the memory it uses.
My first attempt was to have each controller create a store in its init, and remove it in its dealloc. This didn't work, because background threads were still using NSManagedObjects in that store; it was being removed while it was still being used, and things broke.
My second attempt was to wrap the stores in an object that could remove the real store once the wrapped object's retain count hit zero. That way, the background threads could retain the wrapped store, and it would only be removed once nothing was using it any more. I used message forwarding to create a proxy object, like so:
#interface MyStoreWrapper : NSObject
#property (nonatomic, retain) NSPersistentStore *persistentStore;
+(MyStoreWrapper *) wrappedInMemoryStore;
+(MyStoreWrapper *) wrapStore:(NSPersistentStore *)aStore;
-(id) initWithStore:(NSPersistentStore *)aStore;
#end
#implementation MyStoreWrapper
#synthesize persistentStore;
+(MyStoreWrapper *)wrappedInMemoryStore
{
NSError *error = nil;
NSPersistentStore *store = [[[MyAppDelegate sharedDelegate] persistentStoreCoordinator] addPersistentStoreWithType:NSInMemoryStoreType configuration:nil URL:nil options:nil error:&error];
if (error)
{
[NSException raise:#"Core data error" format:#"Could not add temporary store: %#, %#", error, [error userInfo]];
}
return [self wrapStore:store];
}
+(MyStoreWrapper *)wrapStore:(NSPersistentStore *)aStore
{
return [[[self alloc] initWithStore:aStore] autorelease];
}
-(id)initWithStore:(NSPersistentStore *)aStore
{
self = [super init];
if (self)
{
self.persistentStore = aStore;
}
return self;
}
-(void)dealloc
{
NSError *error = nil;
[[[MyAppDelegate sharedDelegate] persistentStoreCoordinator] removePersistentStore:self.persistentStore error:&error];
if (error)
{
[NSException raise:#"Core data error" format:#"Could not remove temporary store: %#, %#", error, [error userInfo]];
}
[super dealloc];
}
- (void)forwardInvocation:(NSInvocation *)anInvocation
{
if ([self.persistentStore respondsToSelector:[anInvocation selector]])
{
[anInvocation invokeWithTarget:self.persistentStore];
}
else
{
[super forwardInvocation:anInvocation];
}
}
- (BOOL)respondsToSelector:(SEL)aSelector
{
if ([super respondsToSelector:aSelector])
{
return YES;
}
else
{
return [self.persistentStore respondsToSelector:aSelector];
}
}
- (NSMethodSignature*)methodSignatureForSelector:(SEL)aSelector
{
NSMethodSignature* signature = [super methodSignatureForSelector:aSelector];
if (!signature)
{
signature = [self.persistentStore methodSignatureForSelector:aSelector];
}
return signature;
}
+(BOOL)instancesRespondToSelector:(SEL)aSelector
{
if ([super instancesRespondToSelector:aSelector])
{
return YES;
}
else
{
return [NSPersistentStore instancesRespondToSelector:aSelector];
}
}
+(NSMethodSignature *)instanceMethodSignatureForSelector:(SEL)aSelector
{
NSMethodSignature* signature = [super instanceMethodSignatureForSelector:aSelector];
if (!signature)
{
signature = [NSPersistentStore instanceMethodSignatureForSelector:aSelector];
}
return signature;
}
#end
...but this wrapped object doesn't seem to be a valid substitute in e.g. NSFetchRequests.
Have I made some mistake in my wrapper class? Is there some other way to remove an NSPersistentStore from my coordinator once it is unused?
You can't have a question that says both Once the store is unused and then because background threads were still using NSManagedObjects in that store.
By definition, if background threads are still using it, it's not unused ;)
Your method is correct but you are deallocing too early. Your background threads should be retaining the store if they are interested in it's contents. That way, as soon as all your background threads are finished, they will call release and the store will dealloc itself safely.
i am working with Mapkit and i am on SDK 4.2, i am having a strange bug here, in fact i have 3 annotation types, "blue.png", red.png,black.png. I am loading these by a flux and depending on the type its will select these annotation types. Everything works fine when the map is loaded i have the the different annotation view, but when i move , zoom in or zoom out the annotation view changes i.e where it was supposed to be blue.png it becomes black.png.
I am actually testing it on device.
Thank you very much :)
Hey veer the problem is that this method is called if the user pans the map to view another location and then comes back to the place where the annotations are plotted.
- (MKAnnotationView *)mapView:(MKMapView *)mapview viewForAnnotation:(id <MKAnnotation>)annotation
I have seen many sample code for map application and this in what most of the people are using.
- (MKAnnotationView *)mapView:(MKMapView *)mapview viewForAnnotation:(id <MKAnnotation>)annotation
{
if ([annotation isKindOfClass:[MKUserLocation class]])
return nil;
static NSString* AnnotationIdentifier = #"AnnotationIdentifier";
MKAnnotationView *annotationView = [mapView dequeueReusableAnnotationViewWithIdentifier:AnnotationIdentifier];
if(annotationView)
return annotationView;
else
{
MKPinAnnotationView* pinView = [[[MKPinAnnotationView alloc]
initWithAnnotation:annotation reuseIdentifier:AnnotationIdentifier] autorelease];
pinView.animatesDrop=YES;
pinView.canShowCallout=YES;
pinView.draggable = YES;
pinView.pinColor = MKPinAnnotationColorGreen;
return pinView;
}
return nil;
}
i found the solution - in fact i am using a custom annotation view and having 3 diff types of images :
Soln:
- (AnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation
{
AnnotationView *annotationView = nil;
// determine the type of annotation, and produce the correct type of annotation view for it.
AnnotationDetails* myAnnotation = (AnnotationDetails *)annotation;
if(myAnnotation.annotationType == AnnotationTypeGeo)
{
// annotation for your current position
NSString* identifier = #"geo";
AnnotationView *newAnnotationView = (AnnotationView *)[self.mapView dequeueReusableAnnotationViewWithIdentifier:identifier];
if(nil == newAnnotationView)
{
newAnnotationView = [[[AnnotationView alloc] initWithAnnotation:myAnnotation reuseIdentifier:identifier] autorelease];
}
annotationView = newAnnotationView;
}
else if(myAnnotation.annotationType == AnnotationTypeMyfriends)
{
NSString* identifier = #"friends";
AnnotationView *newAnnotationView = (AnnotationView *)[self.mapView dequeueReusableAnnotationViewWithIdentifier:identifier];
if(nil == newAnnotationView)
{
newAnnotationView = [[[AnnotationView alloc] initWithAnnotation:myAnnotation reuseIdentifier:identifier] autorelease];
}
annotationView = newAnnotationView;
}
}