How to create custom exception in objective c? - iphone

I am trying to achieve something like this in objective c.
#try{
//some code that will raise exception
}
#catch(CustomException e){//How to create this
//catching mechanism
}
#catch(NSException e){
//Generic catch
}
I need to create CustomException class and use it. Could you please help me in creating this CustomException and guide me in how to use this.
Thanks in advance.

Exceptions are very rarely used for control flow like this in Objective-C. I'm guessing you have a Java (or similar) background.
I'm not saying that you can't write code like this but it will feel very strange for other people looking at your code and could also possibly work badly if used by other peoples code if you don't completely isolate the exceptions so that it never reaches their code.
How it is commonly done in Objective-C
Exceptions are used for critical errors. If the error is expected (like it seems to be since you want to #try it) you should instead try and return an NSError. This is a design pattern that is used all over the Foundation and Cocoa frameworks and also third party frameworks. Look for example at networking, file reading/writing or JSON code (JSONObjectWithData:options:error:)
What you would do
What you do is add a error parameter (double pointer) at the end of your method that could fail, like this:
- (MyResultObject *)myMethodThatCouldFailWith:(MyObject *)myObject
error:(NSError **)error;
When someone (you or someone else) uses this method they can if they want to pass a NSError pointer that will get set if an error occurred, like this:
NSError *error = nil; // Assume no error
MyResultObject *result = [self myMethodThatCouldFailWith:myObject
error:&error];
if (!result) {
// An error occurred, you can check the error object for more information.
}
Note the ampersand (&) before the error parameter. This means that you are sending your error points as the argument so that inside the risky method that pointer can be changed to points to a new NSError object which can be read after the method returns.
Now, inside your method that could fail, you would set the error to a new NSError object if something went wrong (instead of raising an exception). It is also very common to return nil when an error occurs since that probably means that the calculation won't be able to complete or that the data is unreliable or irrelevant.
- (MyResultObject *)myMethodThatCouldFailWith:(MyObject *)myObject
error:(NSError **)error {
// Do something "risky" ...
MyResultObject *result = [MyResultObject somethingRiskyWith:myObject];
// Determine if things went wrong
if (!result) {
// Set error if a pointer for the error was given
if (error != NULL) {
*error = [NSError errorWithDomain:yourErrorDomain
code:yourErrorCode
userInfo:optionalDictionaryOfExtraInfo];
}
return nil;
}
// Everything went fine.
return result;
}
Now if the error returns you can identify what kind of error it was from the error code that you specified and you can read more detailed information in the user info dictionary (where you can add lots of information).

In the simplest case, I can declare a class using...
#interface CustomException : NSException
#end
#implementation CustomException
#end
...and the code is very much like what you posted:
#try{
#throw [[CustomException alloc] initWithName:#"Custom" reason:#"Testing" userInfo:nil];
}
#catch(CustomException *ce){
NSLog(#"Caught custom exception");
}
#catch(NSException *e){
NSLog(#"Caught generic exception");
}

Related

Parse saveInBackgroundWithBlock additional task

What I want to do is cause another save anytime saveInBackgroundWithBlock is called in my app. Im doing this to create a "log" of everything that changes and who changed it. I looked into the PFObject.h but I am not sure how to properly write this in Obj-C or where else/how I could do this other than going through and adding it to every single instance. Is this a good way to do it? Or should I stick it out and use the harder way?
- (void)saveInBackgroundWithBlock:(nullable PFBooleanResultBlock)block;
you have multiple ways in order to achieve this kind of functionality:
Create Util class which receive PFObject and PFBooleanResultBlock as parameters this Util class will execute a call to saveInBackgroundWithBlock inside the callback you can implement the additional save that you need. at the end your Util class should look like the following:
#interface ParseUtils : NSObject
+ (void)saveParseObject:(PFObject *)object block:(PFBooleanResultBlock)block;
#end
#implementation ParseUtils
+ (void)saveParseObject:(PFObject *)object block:(PFBooleanResultBlock)block {
// if the object is nil or it was not changed return
if (!object || !object.isDirty) return;
[object saveInBackgroundWithBlock:^(BOOL succeeded, NSError * _Nullable error) {
// if no error occured
if (!error){
// HERE YOU SHOULD CALL YOUR ADDITIONAL SAVE...
}
// handle the callback to the calling class
if (block){
block(succeeded,error);
}
}];
}
#end
Another option is to do the same but with singleton (if you created some REST Client singleton for your project)
Another nice option is to create category on top of the PFObject and there to create a method which do exactly the same like the method that of the util
There are more options but i think that it's enough..
if you want to do it as quick as possible use the utilities. if you want to do it with best architecture then go with the category.

AFNetworking nested calll [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Questions concerning problems with code you've written must describe the specific problem — and include valid code to reproduce it — in the question itself. See SSCCE.org for guidance.
Closed 9 years ago.
Improve this question
Right now, I got a GET request, after it's finished, I got the json back, and then I want to use the id from the json to execute another fetch request. It's like a nested fetch request right after another. For example:
+ (void)searchPhotoWithTags:(NSArray *)tags page:(NSInteger)page perPage:(NSInteger)perPage completionBlock:(void (^)(NSArray *, NSError *))block
{
NSDictionary *dict = #{#"method": #"search", #"api_key": kAppKey, #"tags": [tags componentsJoinedByString:#","], #"per_page": [NSString stringWithFormat:#"%d", perPage], #"page": [NSString stringWithFormat:#"%d", page], #"format": #"json"};
[[LDHttpClient sharedClient] getPath:#"" parameters:dict success:^(AFHTTPRequestOperation *operation, id responseObject) {
[[responseObject valueForKeyPath:#"photos.photo"] enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
Photo *photo = [[Photo alloc] initWithPhotoId:[NSNumber numberWithInt:[obj[#"id"] integerValue]] andSecret:obj[#"secret"]];
//down below, I want to use photo.photoId to execute another request but the data is not completed. what's the better way to do this?
[PhotoSize getPhotoSizesWithPhotoId:photo.photoId completionBlock:^(NSArray *photoSizes, NSError *error) {
[photos addObject:#{#"photo": photo, #"sizes": photoSizes}];
}];
}];
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
}];
}
If I understood your question correctly, I think what you're witnessing is a problem of asynchronous.
You are trying to loop through your photos dictionary, getting the photo size of each photo by means of sending another GET request which is an asynchronous operation. However, because of that, the next iteration of your loop already executes before your previous asynchronous operation has finished.
In this case, what you can do is use recursion to help you "iterate" or "loop" through your photos dictionary.
Requirements
For the below code to work, you'll need to create 2 properties
A property for storing your "photos" NSDictionary (e.g. NSDictionary *photosDict) in yourClass.h file
Another property for storing the enumerator of "photos" NSDictionary, which will be of type NSEnumerator, maybe call it "photosEnum"
Cleaning up your code a bit
In your original method, store the photos dictionary and from that, store the photosEnum enumerator too:
+ (void)searchPhotoWithTags:(NSArray *)tags page:(NSInteger)page perPage:(NSInteger)perPage completionBlock:(void (^)(NSArray *, NSError *))block
{
NSDictionary *dict = #{#"method": #"search", #"api_key": kAppKey, #"tags": [tags componentsJoinedByString:#","], #"per_page": [NSString stringWithFormat:#"%d", perPage], #"page": [NSString stringWithFormat:#"%d", page], #"format": #"json"};
[[LDHttpClient sharedClient] getPath:#"" parameters:dict success:^(AFHTTPRequestOperation *operation, id responseObject) {
// I assume you have a property of type NSDictionary created called "photos"
self.photosDict = [responseObject valueForKeyPath:#"photos"];
// Also create a property for the enumerator of type NSEnumerator
self.photosEnum = [self.photosDict objectEnumerator];
// ----------------------------------------------------------
// First call of our recursion method
//
// This will start our "looping" of our photos enumerator
// -----------------------------------------------------------
[self processPhotoDictionary];
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Failed to get photos, error: %#", [error localizedDescription]);
}];
}
And finally, our recursion method does the processing of the photoSizes:
-(void)processPhotoDictionary
{
// ------------------------------------------------------
// Because self.photosEnum is a property of our class
// it remembers where it is "up to" in the "looping"
// ------------------------------------------------------
NSDictionary *photo = [self.photosEnum nextObject];
if(photo != nil)
{
Photo *photoObj = [[Photo alloc] initWithPhotoId:[NSNumber numberWithInt:[[photo valueForKey:#"id"] integerValue]]
andSecret:[photo valueForKey:#"secret"]];
[PhotoSize getPhotoSizesWithPhotoId:photoObj.photoId completionBlock:^(NSArray *photoSizes, NSError *error) {
[photos addObject:#{#"photo": photoObj, #"sizes": photoSizes}];
// ------------------------------------------------------
// Here we're using recursion to iterate through our
// enumerator due to asynchronous nature instead of the
// while loop.
// ------------------------------------------------------
[self processPhotoDictionary];
}];
}
}
Hope that helps.
In addition to the excellent answer of #Zhang, I would like to describe the common problem the OP is facing and how a "general solution" to this common problem may look like.
The common objective is:
Fetch a list of items from a server. Each item contains a URL which points to some other resource (an image for example).
When the list has been received, for each item in the list, fetch the resource (the image) given by the URL.
When implementing this in synchronous style the solution is obvious, and actually quite easy. However, when employing asynchronous style - which is the preferred way when doing networking - a workable solution becomes surprisingly complex, unless you know how to solve such problems ;)
The interesting part here is #2. Part #1 can be simply accomplished via an asynchronous call and a completion function where the completion function invokes part #2.
In order to make the things more easy to understand I will make a few simplifications and a few prerequisites:
In part #1 we obtain a list of elements, say an NSArray object containing our elements. Each element has a property, which is a URL to another resource.
Now, we can easily make the assumption that we already have an array of elements representing the N input values which shall be asynchronously processed in a loop - one after the other. Let us name that array "Source Array".
We will deal with asynchronous methods/functions. One way to have the method/function signal that it is finished with processing something asynchronously is a completion handler (a block).
The common signature for all completion handlers will be defined as follows:
typedef void (^completion_t)(id result);
Note: result shall represent the eventual result of the asynchronous function or method. It may be the kind of thing we expect (an image for example), or it may indicate an error, for example through passing and NSError object.
In oder to implement our part #2, we need an asynchronous method/function which takes an input (one element from the Input Array) and produces an output. This corresponds to your "fetch image resource" task. Later we need to apply this method/function for each element of the "Input Array" we got in part #1.
The generic function, a "transform function", will have this signature:
void transform(id input, completion_t completion);
The corresponding method will have this signature:
-(void) transformWithInput:(id)input
completion:(completion_t)completionHandler;
We can define a typedef for the function as below:
typedef void (^transform_t)(id input, completion_t completion);
Notice, that the result of the transform function or method will be passed through the completion handler's parameter. An synchronous function would just have a return value and return the result.
Note: the name "transform" is just a generic name. You can wrap your network request in a method and get such kind of "transform" function. In the OP's example, the URL would be the input parameter and the completion handler's result parameter would be the image fetched from the server (or an error).
Note: this and the following simplifications are just there to make the explanation of the asynchronous pattern easier to understand. In practice an asynchronous function or method may take other input parameters, and the completion handler may also have other parameters.
Now, the more "tricky" part:
Implementing A Loop In Asynchronous Style
Well, this is a bit "different" than in synchronous programming style.
Purposefully, we define some kind of forEach function or method doing this iteration. That function or method is itself asynchronous! And we know now that any asynchronous function or method will have a completion handler.
So, in case of a function we can declare our "forEach" function as follows:
`void transform_each(NSArray* inArray, transform_t task, completion_t completion);`
transform_each sequentially applies an asynchronous transform function task to each object in the input array inArray. When finished processing all inputs, it invokes the completion handler completion.
The completion handler's result parameter is an array containing the result of each transform function in the same order as the corresponding input.
Note: "sequentially" here means, that the inputs are processed one after the other. A variant of that pattern may process the inputs in parallel.
The parameter inArray is our "Input Array" gathered from step #1.
Parameter task is our asynchronous transform function, which can be virtually anything which takes an input and produces an output. It will be our asynchronous "fetch image" task from the OPs example.
And parameter completion is the handler which gets invoked when all inputs have been processed. It's parameter contains the output of each transform function in an array.
The transform_each can be implemented as follows. First we need a "helper" function do_each.
do_each is actually the heart of the whole pattern for implementing loops in an asynchronous style, so you may take a closer look here:
void do_each(NSEnumerator* iter, transform_t task, NSMutableArray* outArray, completion_t completion)
{
id obj = [iter nextObject];
if (obj == nil) {
if (completion)
completion([outArray copy]);
return;
}
task(obj, ^(id result){
[outArray addObject:result];
do_each(iter, task, outArray, completion);
});
}
The interesting part here, and the "common asynchronous pattern" or "idiom" for implementing loops (as a for_each function) is that do_each will be invoked from the completion handler of the transform function. That may look like a recursion, but actually it is not.
Parameter iter points to the current object within the array which shall be processed.
It will also be used to determine the stop condition: when the enumerator points past the end, we get a nil result from method nextObject. This eventually stops the loop.
Otherwise, the transform function task will be called with the current object as input parameter. The object will be asynchronously processed as defined by the task. When finished, the task's completion handler will be invoked. It's parameter result will be the output of the transform function. The handler needs to add the result to the resulting array outArray. Then it invokes the helper do_each again. This seems to be a recursive call, but it is actually not: the former do_each has already been returned. This is just another invocation of do_each.
Once we have that, we can simply complete our transform_each function as shown below:
void transform_each(NSArray* inArray, transform_t task, completion_t completion) {
NSMutableArray* outArray = [[NSMutableArray alloc] initWithCapacity:[inArray count]];
NSEnumerator* iter = [inArray objectEnumerator];
do_each(iter, task, outArray, completion);
}
NSArray Category
For our convenience we can easily create a Category for NSArray with a "forEach" method which asynchronously processes the inputs in sequence:
#interface NSArray (AsyncExtension)
- (void) async_forEachApplyTask:(transform_t) task completion:(completion_t) completion;
#end
#implementation NSArray (AsyncExtension)
- (void) async_forEachApplyTask:(transform_t) task completion:(completion_t) completion {
transform_each(self, task, completion);
}
#end
A code example can be found here on Gist: transform_each
A much more sophisticated concept to solve common asynchronous patterns is to utilize "Futures" or "Promises". I've implemented the concept of a "Promise" for Objective-C in a small library: RXPromise.
The above "loop" can be implemented including a the capability to cancel the asynchronous tasks via RXPromise, and of course a lot more. Have fun ;)
I think I might just solve this problem. I am not sure about it. It just works. I am using AFNetwroking's enqueueBatchOfHTTPRequestOperations function.

Prevent Calculator Syntax Error Crash? Xcode

Currently I am making a Calculator that allows the user to type out the formula they wish.
Ex. ((1+1)**9)+2)
This works just fine, I have used two methods for calculating this.
First:
answer = [[NSExpression expressionWithFormat:typeTo.text, nil] expressionValueWithObject:nil context:nil];
typeTo.text = [NSString stringWithFormat:#"%#", answer];
answerLabel.text = [NSString stringWithFormat:#"ANS { %# }", answer];
Second:
answer = [GCMathParser evaluate:typeTo.text];
Both of these calculate the problem without difficulty. But if the user types in:
(1+1)) [two brackets]
Both ways crash. This is one example of many different syntax errors. Is there a way to easily prevent this?
.
Additional info:
This is the way the second method catches the error:
#ifdef __COCOA_IMPLEMENTATION__
[NSException raise:#"Error in expression" format:#"error = %s", errStr];
#endif
THANKS :D
I haven't used either of those but based on the additional info, it may be throwing an NSException.
If that's the case, you can catch it and handle it. It looks like it might format a useful message telling you what's wrong with with expressions.
#try
{
// do work
}
#catch(NSException* ex)
{
// handle
}
https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/Exceptions/Tasks/HandlingExceptions.html
Also, look to see if those libraries offer functions that pass in a ref to NSError. If so, you can use that.
There's also DDMathParser which is supposed to be a modern math parser and it looks like it takes NSError. Might be worth a look.
http://github.com/davedelong/DDMathParser

Performing selector from within an Objective C block

I have been trying to use objective c blocks for the first time because I have really enjoyed using closures in languages such as Python and Haskell.
I have run into a problem however that I am hoping someone might be able to help with.
Below is a simplest version of the problem I am having.
typedef void(^BlockType)(NSString *string);
- (void)testWithtarget:(id)target action:(SEL)action
{
BlockType block = ^(NSString *string) {
[target performSelector:action withObject:data];
};
block(#"Test String"); // Succeeds
[self performSelector:#selector(doBlock:) withObject:block afterDelay:5.0f];
}
- (void)doBlock:(BlockType)block
{
block(#"Test String 2"); // Causes EXC_BAD_ACCESS crash
}
So it appears to be some sort of memory management issue which doesn't suprise me but I just don't have the knowledge to see the solution. Possibly what I am trying may not even be possible.
Interested to see what other people think :)
The block is not retained, since it is only present on the stack. You need to copy it if you want to use it outside the scope of the current stack (i.e. because you're using afterDelay:).
- (void)testWithtarget:(id)target action:(SEL)action
{
BlockType block = ^(NSString *string) {
[target performSelector:action withObject:data];
};
block(#"Test String"); // Succeeds
[self performSelector:#selector(doBlock:) withObject:[block copy] afterDelay:5.0f];
}
- (void)doBlock:(BlockType)block
{
block(#"Test String 2");
[block release];
}
It's a bit hap-hazard however since you're copying and releasing across method calls, but this is how you'd need to do it in this specific case.

How to write a value validation method for core data?

The docs say:
you should implement methods of the
form validate:error:, as defined by the NSKeyValueCoding protocol
so lets say I have an attribute which is an int: friendAge
I want to make sure that any friend may not be younger than 30. So how would I make that validation method?
-validateFriendAge:error:
What am I gonna do in there, exactly? And what shall I do with that NSError I get passed? I think it has an dictionary where I can return a humanly readable string in an arbitrary language (i.e. the one that's used currently), so I can output a reasonable error like: "Friend is not old enough"... how to do that?
You can do anything you want in there. You can validate that the age is between ranges or any other logic you want.
Assuming there is an issue, you populate the error and have at least a value for the NSLocaliedDescriptionKey. That error will then be handed back to the UI or whatever this value is getting set from and allow you to handle the validation error. This means if there is other useful information you may need in the calling/setting method, you can add it into the NSError here and receive it.
For example:
-(BOOL)validateFreindAge:(NSNumber*)ageValue error:(NSError **)outError
{
if ([ageValue integerValue] <= 0) {
NSString *errorDesc = #"Age cannot be below zero.";
NSDictionary *dictionary = [NSDictionary dictionaryWithObject:errorDesc forKey:NSLocalizedDescriptionKey];
*error = [NSError errorWithDomain:#"MyDomain" code:1123 userInfo:dictionary];
return NO;
}
return YES;
}