-setPrimitiveValue:forKey: won't trigger KVO notifications. But in my brain, KVO only makes sense when something changes. But how can change something when I only access it for read?
-primitiveValueForKey: only gets the object for some key. But it won't modify it. So why would/could this cause KVO notifications when using -valueForKey:?
(Of course there is a point, but I don't see it yet.)
The -primitiveValueForKey: and -setPrimitiveValue:forKey: methods are primarily used by Core Data. In particular, Core Data doesn't just need to know when you're going to modify an attribute; it needs to know when you're going to access it as well, so it can implement faulting.
Thus Core Data adds -{will,did}AccessValueForKey: methods to use in getters, just as -{will,did}ChangeValueForKey: methods exist for use in setters to act as KVO hooks.
However, there's another wrinkle: Core Data actually manages the underlying storage of modeled properties for you as well. So you need some way to manipulate this underlying storage within the barriers established by the -{will,did}{Access,Change}ValueForKey: methods. That's where -primitiveValueForKey: and -setPrimitiveValue:forKey: come in.
This is why the standard pattern for implementing Core Data getters and setters, prior to the existence of #property and #dynamic, looked like this:
// Person.m
#import "Person.h"
#implementation Person
- (NSString *)name {
[self willAccessValueForKey:#"name"];
NSString *value = [self primitiveValueForKey:#"name"];
[self didAccessValueForKey:#"name"];
}
- (void)setName:(NSString *)value {
[self willChangeValueForKey:#"name"];
[self setPrimitiveValue:value forKey:#"name"];
[self didChangeValueForKey:#"name"];
}
#end
Now of course, you can just declare a property and define it as #dynamic if you want Core Data to generate this stuff for you at runtime:
// Person.h
#interface Person : NSManagedObject
#property (nonatomic, readwrite, copy) NSString *name;
#end
// Person.m
#import "Person.h"
#implementation Person
#dynamic name;
#end
There are some situations though where you still want to manipulate the underlying storage without KVO or fault-firing, however. Thus Core Data provides a new way to get at this as well, also built around property declarations and automatic synthesis:
// Person.h
#interface Person : NSManagedObject
#property (nonatomic, readwrite, copy) NSString *name;
#end
// Person.m
#import "Person.h"
#interface Person ()
#property (nonatomic, readwrite, copy) NSString *primitiveName;
#end
#implementation Person
#dynamic name;
#dynamic primitiveName;
#end
Note that I put the class continuation in the .m file; it's not something that code outside Person (or even really code outside -awakeFromInsert and -awakeFromFetch) should touch. But it does let me get at the underlying storage for the "name" property without embedding literal strings in my code, and with the use of the real types.
Related
I've updated my iOS SDK to version 6. After that I've compiled my app (works fine in iOS 4 & iOS 5) but now the location services doesn't work. My delegate isn't receiving any update and the upper location arrow is not appearing... I'm starting the service as the usual way:
[locationManager startUpdatingLocation];
My project is non ARC.
What is happening? This is driving me crazy...
Thanks in advance.
Make sure you have a CFBundleDisplayName in your project's .plist file. Adding that key fixed it for me.
Just set the property pausesLocationUpdatesAutomatically of Location Manager to NO. This is a new feature of IOS 6 that disable Location Updates when application runs in background. The default value of this property is YES.
This is a change in iOS6:
You need to implement locationManager:didUpdateLocations: instead of locationManager:didUpdateToLocation:fromLocation to be notified when the location is updated.
You should also read the documentation about startUpdatingLocation.
In my case, I had the location manager under a different class and I was calling this class from the main controller. This was not working and the didUpdateLocations was not called.
//
// LocationServices.h
//
#import <Foundation/Foundation.h>
#import <CoreLocation/CoreLocation.h>
#interface LocationServices : NSObject <CLLocationManagerDelegate> {
CLLocationManager *locationManager;
}
#property (nonatomic, retain) CLLocationManager *locationManager;
- (void)startLocationServices;
#end
// LocationServices.m
#import "LocationServices.h"
#implementation LocationServices
#synthesize locationManager, currentLocation;
- (void)startLocationServices {
locationManager = [[CLLocationManager alloc] init];
locationManager.delegate = self;
locationManager.pausesLocationUpdatesAutomatically = NO;
locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters;
if ([CLLocationManager locationServicesEnabled]) {
[locationManager startUpdatingLocation];
} else {
NSLog(#"Location services is not enabled");
}
}
////////////////////////////////////////////////
- (void)locationManager:(CLLocationManager *)manager
didUpdateLocations:(NSArray *)locations {
CLLocation* location = [locations lastObject];
NSLog(#"Updated: latitude %+.6f, longitude %+.6f\n",
location.coordinate.latitude,
location.coordinate.longitude);
}
#end
// Main controller
- (void)viewDidLoad {
[super viewDidLoad];
.....
LocationServices *locationSerices = [[LocationServices alloc]init];
[locationSerices startLocationServices];
......
}
The above code does not work. Why? I do not know ....you can easily lose interest when you spend so much time trying to do a thing that is supposed to be simple. iOS is very complicated and unfriendly programming environment. There are many ways to do one thing, only one works, you cannot mix and match without introducing a problem. You have to do everything by the book or you or you get nothing. Not even a hint that you did something wrong ... frustrating ...
Instead when I implemented
locationManager:(CLLocationManager *)manager didUpdateLocations:
in the main controller everything worked fine
The issue seems to be resolved in IOS 6.1 Beta2 - http://www.youtube.com/watch?v=aFZR0eMUV74
setting CFBundleDisplayName solved the problem for me. Same thing location update was never called, just set the info.plist parameter and it start working.
I've tried everything in plist files, cleans, rebuilds, new targets, configurations, etc, etc, etc. Nothing worked. But FINALLY I've fixed it. I had to create a new Xcode 4.5 project from scratch, reconfigure it, add file by file and framework by framework manually. It seems that my old XCode project had something internally incompatible with last XCode. I write this here because maybe it can save someone's next 10 hours of work.
Am I being too simplistic here? Under Privacy, Locations looks the same as it did in previous issues.What's all the fuss about?
NSManagedObject provides access to its NSManagedObjectContext, but does it retain it?
According to "Passing Around a NSManagedObjectContext on iOS" by Marcus Zarra, "The NSManagedObject retains a reference to its NSManagedObjectContext internally and we can access it."
How does Zarra know this and is he correct?
I'm asking because I want to know if the NSManagedObjectContext will be dealloc'ed in the tearDown method below. (I'm using CocoaPlant.)
#import <SenTestingKit/SenTestingKit.h>
#import <CocoaPlant/CocoaPlant.h>
#import "AccountUser.h"
#interface AccountUserTests : SenTestCase {
AccountUser *accountUser;
}
#end
#implementation AccountUserTests
- (void)setUp {
accountUser = [AccountUser insertIntoManagedObjectContext:
[NSManagedObjectContext contextWithStoreType:NSInMemoryStoreType error:NULL]];
}
- (void)tearDown {
[accountUser delete];
}
- (void)testFetchWithLinkedAccountUserID {
// Tests go here...
}
#end
NSManagedObject DOES NOT hold strong reference to its NSManagedObjectContext. I've checked that on a test project.
Therefore, you should keep strong reference to NSManagedObjectContext as long as you use its objects.
Wow, over two years old and no accepted answer here :)
When I wrote that post I did indeed mean it keeps a reference to its associated NSManagedObjectContext. If a NSManagedObject retained the NSManagedObjectContext then it would most likely run into problems.
In either case, whether the MOC is retained by the MO is irrelevant to your application design. If you need the MOC to stay around then you need to retain it (now referred to as a strong reference) or it will go away. What the frameworks do internally is not our problem. We just need to make sure we balance our retains and releases.
Matt,
I think Marcus may have miswrote that a NSManagedObject retains its context. Every NSManagedObject maintains a link to the context. Unless individual objects have an internal retain cycle or are retained outside of their context, then, in my experience, they are all released when the context is released. If they retained the context, then this would almost certainly not be the case.
The above said, you can easily write code to test Marcus' claim. Override -dealloc and log when it is called.
IMO, it is a best practice to retain your context until you are done with it. Depending on an undocumented behavior is probably not wise.
Andrew
SqlAssignementAppDelegate *appDelegate =(SqlAssignementAppDelegate *) [[UIApplication sharedApplication]delegate];
lblresNam.text =[appDelegate.Record objectAtIndex:0];
lblresNam is UITextField type object
Record is NSMutableArray
but my application is terminating..
Please give me solutions...
Is your Record object a property, so you know it's being retained, and so dot notation will be available?
More likely the culprit, did you forget to #synthesize Record so it has a getter?
If you neglected to do either one of those, appDelegate.Record is an error.
I have several subclasses of NSManagedObject. They are all instantiated with code something like this:
MeasurementDescriptor *descriptor = (MeasurementDescriptor *)[NSEntityDescription
insertNewObjectForEntityForName:#"MeasurementDescriptor"
inManagedObjectContext:context];
or like this:
Experiment *experiment = (Experiment *)[NSEntityDescription
insertNewObjectForEntityForName:#"Experiment"
inManagedObjectContext:context];
What is odd, though, is that (from code above)
NSLog(#" descriptor's class = %#", NSStringFromClass([descriptor class]));
prints out 'NSManagedObject', while
NSLog(#" experiment's class = %#", NSStringFromClass([experiment class]));
prints out 'Experiment'.
Does anyone know why this would be? MeasurementDescriptor, unlike my other NSManagedObject subclasses, had no ivars (not including its Core Data properties). Adding an ivar did not change anything. Similarly, MeasurementDescriptor is the only NSManagedObject subclass without 'relationship' properties. Perhaps this accounts for this strangeness...???
The only explaination is that your MeasurementDescriptor subclass is not actually known to the code. The most common causes of this are:
In the data model editor not setting the Class attribute of the entity to the correct class.
Not adding the source file for the subclass to the target.
This is easy to do with Core Data because if it can't find a dedicated subclass it doesn't complain but just returns a generic NSManagedObject initialized with the entity's property key names.
I'm trying a basic test of sorting an NSManagedObject subclass. I set up a basic subclass "TestClass" with two attributes: stringField and numberField. They use the standard Obj-C 2.0 accessor protocol:
#interface TestClass : NSManagedObject
#property (retain) NSString *stringField;
#property (retain) NSNumber *numberField;
#end
#implementation TestClass
#dynamic stringField;
#dynamic numberField;
#end
When I try to fetch instances of this entity, I can fetch based on either attribute. However, if I use a sort descriptor, the numberField is said to not be KVC-compliant.
Within the model, I set the numberField to Int64, but I'm confused. I thought the wrapper (NSNumber) would handle the KVC problem. What do I need to do to make this work?
Some initial "Is the computer on?"-type questions:
Does your model specify that the managed object class for your entity is TestClass?
Are you sure you spelled numberField correctly when specifying the key in your sort descriptor?
Is numberField a transient attribute in your model?
These are the common issues that I can think of that might cause such an error when fetching with a sort descriptor, the first one especially.
Also, this won't affect KVC, but your attributes' property declarations should be (copy) rather than (retain) since they're "value" classes that conform to the NSCopying protocol and may have mutable subclasses. You don't want to pass a mutable string in and mutate it underneath Core Data. (Yeah, there's no NSMutableNumber or NSMutableDate in Cocoa, but that doesn't prevent creating MyMutableNumber or MyMutableDate subclasses...)