I have 3 entities that I generated with MOGenerator, I'd like to be able to get one of them back from their objectID
I tried this :
- (void)aMethod: (SpecialEntity1ID *)entityID
{
//This is a method from MagicalRecord but it doesn't matter(I think...).
NSManagedObjectContext *context = [NSManagedObjectContext MR_contextWithParent:[NSManagedObjectContext MR_defaultContext]];
SpecialEntity1 *entity1 = [context objectRegisteredForID:entityID]
//But this returns an NSManagedObject so it doesn't work...
}
Could someone help me get this object back with its ID ?
Since I don't know how to do it with the ID I'm currently working around it by making a method with an NSStringas a paramater instead of SecialEntity1ID that defines one of the attribute of this object (and is unique) and fetching the object.
I think getting back with his ID is better so any idea ?
You want to use existingObjectWithID:error: method of your NSManagedObjectContext and typecast the return type if you are 100% sure what it will be. I'd keep it generic i.e. let it return an NSManagedObject and then test its class elsewhere if you want to determine whether it belongs to a particular class.
- (Object*)retrieveObjectWithID:(ObjectID*)theID
{
NSError *error = nil;
Object *theObject = (Object*)[[NSManagedObjectContext contextForCurrentThread] existingObjectWithID:theID error:&error];
if (error)
NSLog (#"Error retrieving object with ID %#: %#", theID, error);
return theObject;
}
I've been trying this Twitter api stuff and it's really confusing...
I keep getting EXC_BAD_ACCESS bad access with the following code... What is the problem here?
NSURL *followingURL = [NSURL URLWithString:#"https://api.twitter.com/1/users/lookup.json"];
// Pass in the parameters (basically '.ids.json?screen_name=[screen_name]')
id fromIntToNum = [NSNumber numberWithInteger: friID];
NSDictionary *parameters = [NSDictionary dictionaryWithObjectsAndKeys:#"159462573", #"user_id", nil];
// Setup the request
twitterRequest = [[TWRequest alloc] initWithURL:followingURL
parameters:parameters
requestMethod:TWRequestMethodGET];
// This is important! Set the account for the request so we can do an authenticated request. Without this you cannot get the followers for private accounts and Twitter may also return an error if you're doing too many requests
[twitterRequest setAccount:theAccount];
// Perform the request for Twitter friends
[twitterRequest performRequestWithHandler:^(NSData *responseData, NSHTTPURLResponse *urlResponse, NSError *error) {
if (error) {
/*
// deal with any errors - keep in mind, though you may receive a valid response that contains an error, so you may want to look at the response and ensure no 'error:' key is present in the dictionary
NSLog(#"%#",error);*/
} else {
/*NSError *jsonError = nil;
// Convert the response into a dictionary
NSDictionary *twitterGrabbedUserInfo = [NSJSONSerialization JSONObjectWithData:responseData options:NSJSONWritingPrettyPrinted error:&jsonError];
// Grab the Ids that Twitter returned and add them to the dictionary we created earlier
NSLog(#"%#", [twitterGrabbedUserInfo objectForKey:#"screen_name"]);*/
}
}];
I separated the line the my code fails on...
What could be causing this Twitter API problem?
The following line causes the crash:::
[twitterRequest performRequestWithHandler:^(NSData *responseData,
NSHTTPURLResponse *urlResponse, NSError *error) {
I will also sometimes get this error:
[__NSCFNumber credentialForAccount:]: unrecognized
UPDATE: I commented out the handler and I made TwitterRequest and ivar, but it still crashes...
In your block you look for an error, but if you get one you log it and continue on. You should put an "else" statement in and only proceed if no error.
Why not try to comment out all your code in the handler - don't do anything - and see if you get the crash. Then try with just the error code. Then try with the JSON serialization, and finally the last line. If you can find the part of the block that is causing the problem that would help.
Also, I suspect that performRequestWithHandler: does not block, but expects you to notify your class within the block that the request is done. If so it means "TWRequest *twitterRequest" should be an ivar or property, and you need to allows for some method to get called when the handler is done. Your crash may be due to ARC reallocating your object while the object is running.
EDIT:
Note that that the TWRequest class description says: "Use the initWithURL:parameters:requestMethod: method to initialize a newly created TWRequest object passing the required property values. " It says PLURAL properties, meaning more than 1. Could it be that it also expects a "credentialForAccount" property? You have to read the twitter docs to find all the required properties.
EDIT2:
Well, we don't even know if you get as far as your handler. Put a NSLog there but I suspect its never getting that far. If true this leaves three possibilities:
a) it does't like the URL (although this seems good)
b) you are missing some parameters it expects
c) id doesn't like "theAccount" object - is it a valid ACAccount object? Try NSLogging it.
It has to be one of these three things.
I had similar issues with iOS5 and TWRequest, and the problem turned out to be the ACAccountStore being released before the request handler block was called. The following code fixed this for me:
__weak ACAccountStore *wAccountStore = accountStore;
[request performRequestWithHandler:^(NSData *responseData, NSHTTPURLResponse *urlResponse, NSError *error) {
__strong ACAccountStore *sAccountStore = wAccountStore;
// handle the finished request here
// to silence Xcode warning 'unused variable'
// not necessary for releasing sAccountStore,
// it will go out of scope anyway when the block ends
sAccountStore = nil;
}];
This way, the accountStore gets retained until the block finishes.
I'm working on an iCloud compatible app and I am researching how to detect whether a file is being uploaded/downloaded or has completed that. I found that this can be detected with NSURL "keys," such as NSURLUbiquitousItemIsDownloadingKey or NSURLUbiquitousItemIsUploadingKey. I'm still working on learning about programming, so what are these keys? How can I use them to detect the status of the files (I want the app to know when a file is done uploading to iCloud or done downloading (whichever side the device is on)).
I read that I can use resourceValuesForKeys:error: to query the state of these keys, so would I put this into an IF statement and see if the result is expected, such as "yes" or "no"? Thanks for your help.
if ([destination resourceValuesForKeys:[NSArray arrayWithObject:NSURLUbiquitousItemIsUploadingKey] error:NULL]) {
//is uploading??
}
Your proposed code looks almost workable, but for one thing: resourceValuesForKeys:error: returns a dictionary whose keys are the same as the constants you pass in and whose values are as specified in the documentation for those keys. In the case of NSURLUbiquitousItemIsUploadingKey, the value is an NSNumber instance wrapping a BOOL value.
So... assuming destination is an NSURL pointing to an item in your ubiquity container:
NSError *error;
NSArray *keys = [NSArray arrayWithObject:NSURLUbiquitousItemIsUploadingKey];
NSDictionary *values = [destination resourceValuesForKeys:keys error:&error];
if (values == nil)
NSLog(#"error: %#", error);
else if ([[values objectForKey:NSURLUbiquitousItemIsUploadingKey] boolValue])
NSLog(#"uploading");
else
NSLog(#"not uploading");
If you're only querying one key, you can use getResourceValue:forKey:error: to be a little more concise.
I am working on catching errors in my app, and I am looking into using NSError. I am slightly confused about how to use it, and how to populate it.
Could someone provide an example on how I populate then use NSError?
Well, what I usually do is have my methods that could error-out at runtime take a reference to a NSError pointer. If something does indeed go wrong in that method, I can populate the NSError reference with error data and return nil from the method.
Example:
- (id) endWorldHunger:(id)largeAmountsOfMonies error:(NSError**)error {
// begin feeding the world's children...
// it's all going well until....
if (ohNoImOutOfMonies) {
// sad, we can't solve world hunger, but we can let people know what went wrong!
// init dictionary to be used to populate error object
NSMutableDictionary* details = [NSMutableDictionary dictionary];
[details setValue:#"ran out of money" forKey:NSLocalizedDescriptionKey];
// populate the error object with the details
*error = [NSError errorWithDomain:#"world" code:200 userInfo:details];
// we couldn't feed the world's children...return nil..sniffle...sniffle
return nil;
}
// wohoo! We fed the world's children. The world is now in lots of debt. But who cares?
return YES;
}
We can then use the method like this. Don't even bother to inspect the error object unless the method returns nil:
// initialize NSError object
NSError* error = nil;
// try to feed the world
id yayOrNay = [self endWorldHunger:smallAmountsOfMonies error:&error];
if (!yayOrNay) {
// inspect error
NSLog(#"%#", [error localizedDescription]);
}
// otherwise the world has been fed. Wow, your code must rock.
We were able to access the error's localizedDescription because we set a value for NSLocalizedDescriptionKey.
The best place for more information is Apple's documentation. It really is good.
There is also a nice, simple tutorial on Cocoa Is My Girlfriend.
I would like to add some more suggestions based on my most recent implementation. I've looked at some code from Apple and I think my code behaves in much the same way.
The posts above already explain how to create NSError objects and return them, so I won't bother with that part. I'll just try to suggest a good way to integrate errors (codes, messages) in your own app.
I recommend creating 1 header that will be an overview of all the errors of your domain (i.e. app, library, etc..). My current header looks like this:
FSError.h
FOUNDATION_EXPORT NSString *const FSMyAppErrorDomain;
enum {
FSUserNotLoggedInError = 1000,
FSUserLogoutFailedError,
FSProfileParsingFailedError,
FSProfileBadLoginError,
FSFNIDParsingFailedError,
};
FSError.m
#import "FSError.h"
NSString *const FSMyAppErrorDomain = #"com.felis.myapp";
Now when using the above values for errors, Apple will create some basic standard error message for your app. An error could be created like the following:
+ (FSProfileInfo *)profileInfoWithData:(NSData *)data error:(NSError **)error
{
FSProfileInfo *profileInfo = [[FSProfileInfo alloc] init];
if (profileInfo)
{
/* ... lots of parsing code here ... */
if (profileInfo.username == nil)
{
*error = [NSError errorWithDomain:FSMyAppErrorDomain code:FSProfileParsingFailedError userInfo:nil];
return nil;
}
}
return profileInfo;
}
The standard Apple-generated error message (error.localizedDescription) for the above code will look like the following:
Error Domain=com.felis.myapp Code=1002 "The operation couldn’t be completed. (com.felis.myapp error 1002.)"
The above is already quite helpful for a developer, since the message displays the domain where the error occured and the corresponding error code. End users will have no clue what error code 1002 means though, so now we need to implement some nice messages for each code.
For the error messages we have to keep localisation in mind (even if we don't implement localized messages right away). I've used the following approach in my current project:
1) create a strings file that will contain the errors. Strings files are easily localizable. The file could look like the following:
FSError.strings
"1000" = "User not logged in.";
"1001" = "Logout failed.";
"1002" = "Parser failed.";
"1003" = "Incorrect username or password.";
"1004" = "Failed to parse FNID."
2) Add macros to convert integer codes to localized error messages. I've used 2 macros in my Constants+Macros.h file. I always include this file in the prefix header (MyApp-Prefix.pch) for convenience.
Constants+Macros.h
// error handling ...
#define FS_ERROR_KEY(code) [NSString stringWithFormat:#"%d", code]
#define FS_ERROR_LOCALIZED_DESCRIPTION(code) NSLocalizedStringFromTable(FS_ERROR_KEY(code), #"FSError", nil)
3) Now it's easy to show a user friendly error message based on an error code. An example:
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Error"
message:FS_ERROR_LOCALIZED_DESCRIPTION(error.code)
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alert show];
Great answer Alex. One potential issue is the NULL dereference. Apple's reference on Creating and Returning NSError objects
...
[details setValue:#"ran out of money" forKey:NSLocalizedDescriptionKey];
if (error != NULL) {
// populate the error object with the details
*error = [NSError errorWithDomain:#"world" code:200 userInfo:details];
}
// we couldn't feed the world's children...return nil..sniffle...sniffle
return nil;
...
Objective-C
NSError *err = [NSError errorWithDomain:#"some_domain"
code:100
userInfo:#{
NSLocalizedDescriptionKey:#"Something went wrong"
}];
Swift 3
let error = NSError(domain: "some_domain",
code: 100,
userInfo: [NSLocalizedDescriptionKey: "Something went wrong"])
Please refer following tutorial
i hope it will helpful for you but prior you have to read documentation of NSError
This is very interesting link i found recently ErrorHandling
I'll try summarize the great answer by Alex and the jlmendezbonini's point, adding a modification that will make everything ARC compatible (so far it's not since ARC will complain since you should return id, which means "any object", but BOOL is not an object type).
- (BOOL) endWorldHunger:(id)largeAmountsOfMonies error:(NSError**)error {
// begin feeding the world's children...
// it's all going well until....
if (ohNoImOutOfMonies) {
// sad, we can't solve world hunger, but we can let people know what went wrong!
// init dictionary to be used to populate error object
NSMutableDictionary* details = [NSMutableDictionary dictionary];
[details setValue:#"ran out of money" forKey:NSLocalizedDescriptionKey];
// populate the error object with the details
if (error != NULL) {
// populate the error object with the details
*error = [NSError errorWithDomain:#"world" code:200 userInfo:details];
}
// we couldn't feed the world's children...return nil..sniffle...sniffle
return NO;
}
// wohoo! We fed the world's children. The world is now in lots of debt. But who cares?
return YES;
}
Now instead of checking for the return value of our method call, we check whether error is still nil. If it's not we have a problem.
// initialize NSError object
NSError* error = nil;
// try to feed the world
BOOL success = [self endWorldHunger:smallAmountsOfMonies error:&error];
if (!success) {
// inspect error
NSLog(#"%#", [error localizedDescription]);
}
// otherwise the world has been fed. Wow, your code must rock.
Another design pattern that I have seen involves using blocks, which is especially useful when a method is being run asynchronously.
Say we have the following error codes defined:
typedef NS_ENUM(NSInteger, MyErrorCodes) {
MyErrorCodesEmptyString = 500,
MyErrorCodesInvalidURL,
MyErrorCodesUnableToReachHost,
};
You would define your method that can raise an error like so:
- (void)getContentsOfURL:(NSString *)path success:(void(^)(NSString *html))success failure:(void(^)(NSError *error))failure {
if (path.length == 0) {
if (failure) {
failure([NSError errorWithDomain:#"com.example" code:MyErrorCodesEmptyString userInfo:nil]);
}
return;
}
NSString *htmlContents = #"";
// Exercise for the reader: get the contents at that URL or raise another error.
if (success) {
success(htmlContents);
}
}
And then when you call it, you don't need to worry about declaring the NSError object (code completion will do it for you), or checking the returning value. You can just supply two blocks: one that will get called when there is an exception, and one that gets called when it succeeds:
[self getContentsOfURL:#"http://google.com" success:^(NSString *html) {
NSLog(#"Contents: %#", html);
} failure:^(NSError *error) {
NSLog(#"Failed to get contents: %#", error);
if (error.code == MyErrorCodesEmptyString) { // make sure to check the domain too
NSLog(#"You must provide a non-empty string");
}
}];
extension NSError {
static func defaultError() -> NSError {
return NSError(domain: "com.app.error.domain", code: 0, userInfo: [NSLocalizedDescriptionKey: "Something went wrong."])
}
}
which I can use NSError.defaultError() whenever I don't have valid error object.
let error = NSError.defaultError()
print(error.localizedDescription) //Something went wrong.
Well it's a little bit out of question scope but in case you don't have an option for NSError you can always display the Low level error:
NSLog(#"Error = %# ",[NSString stringWithUTF8String:strerror(errno)]);
The method in question (actually a polymorphically-implemented family of recursive search methods) returns a pointer to a certain type of object. I had been returning nil in cases of failure. Now I want to have two different kinds of failure. What is the easiest way to implement that?
The best way to do this is to keep the return nil;, but take an error pointer as one of the function arguments. This way, you can send in an error, and check it for a value afterward to see what happened. Your function will still run, but you'll have some control over what gets returned.
As an example, here's some code I use for saving a managedObjectContext:
NSManagedObjectContext *moc = [self managedObjectContext];
NSError *error;
if (![moc save:&error]) {
NSString *description = [error localizeDescription];
NSInteger code = [error code];
}
I've tweaked the inside of the block to show a couple of the ways to pull info out of an error. For you, it'd probably be best to use simple error codes to distinguish between different nil values.
Here's a code example (though probably not the best way, as you'll have to duplicate code to interpret the error messages):
-(id) functionCall:(NSError *)error {
...
if (nilCondition) {
if (firstNilCondition) {
[error setCode:1];
}
if (firstNilCondition) {
[error setCode:2];
}
return nil;
}
}