Problem with stringByEvaluatingJavaScriptFromString - iphone

I wanna to know abt "stringByEvaluatingJavaScriptFromString".
According to the apple doc.
"The result of running script or nil if it fails."
I have a method in which inside a for loop i'm passing a string value to stringByEvaluatingJavaScriptFromString. what will it do ?? will this get response for every string or something else will happen??
I was doing like this...
- (void)loadWithStartPoint:(NSString *)startPoint endPoint:(NSMutableArray *)endPoints options:(UICGDirectionsOptions *)options {
for (int idx = 0; idx < [endPoints count]; idx ++)
{
NSString *msg = [NSString stringWithFormat:#"loadDirections('%#', '%#', %#)", startPoint, [endPoints objectAtIndex:idx], [options JSONRepresentation]];
[googleMapsAPI stringByEvaluatingJavaScriptFromString:msg];
}
}
Inorder to get response to every string what should I do? I think that it should get response to every string that i'm passing here. Please tell me what m doing wrong and how would i manipulate my code to get response to all strings that m passing.
Any help would be appreciated .Thnx in advance.

You should make your javascript method to return a default string or something if even an error occurs in the script.
function loadDirections()
{
try
{
//Your code goes here which returns some result
}
catch(err)
{
var errorFlag = "ERROR";
return errorFlag;
}
}
and then you should alter your Objective C code like below
NSString *msg = [NSString stringWithFormat:#"loadDirections('%#', '%#', %#)", startPoint, [endPoints objectAtIndex:idx], [options JSONRepresentation]];
if([msg isEqualToString:#"ERROR")
{
//Do some error handling
}
else
{
//Your actual code goes here
}
Update for the comment:
To solve your javascript asynchronous problem either (1) you can change your design and call the javascript method only after getting response from the first call (2) or else you can use NSTimer which will will give a little time for the execution. In my opinion changing your design as per the first option would be perfect.
Have a look at these questions
stringByEvaluatingJavaScriptFromString doesn't always seem to work
return value javascript UIWebView

Related

osip_message_to_str fails on a message I created using the message/parser functions

I'm trying to receive an invite message and then reply with 100 trying and/or 180 ringing to the same client. I'd like to use only the parser from libosip2.
So when I try to osip_message_to_str so I have a buffer to send back, it always fails with -2.
I tried cloning all the fields I thought it would make sense. But still having the same issue.
If I try to osip_message_to_str on the message I received, it works well.
parser_init();
osip_message_t *request = received_buffer(buffer); // the message is received properly from the buffer
osip_message_t *response;
int i = osip_message_init(&response);
if (i != 0) {
fprintf(stderr, "cannot allocate\n");
return -1;
}
osip_message_set_version(response, strdup("SIP/2.0"));
osip_message_set_status_code(response, 100);
osip_from_clone(request->from, &response->from);
osip_to_clone(request->to, &response->to); /* include the tag! */
osip_call_id_clone(request->call_id, &response->call_id);
osip_contact_t *contact = nullptr;
osip_message_get_contact(response, 0, &contact);
osip_uri_clone(osip_contact_get_url(contact), &response->req_uri);
osip_cseq_clone(request->cseq, &(response->cseq));
char *dest = NULL;
size_t length = 0;
i = osip_message_to_str(response, &dest, &length);
if (i != 0) {
fprintf(stderr, "resp cannot get printable message %d\n", i);
return -1;
}
fprintf(stdout, "message:\n%s\n", dest);
I expect to be able to print a response message.
From libosip2, file osip_port.h, the error return code -2 means bad parameter:
#define OSIP_BADPARAMETER -2
The first line of an answer is something like this: "SIP/2.0 100 Trying".
In your code, you are setting correctly both "SIP/2.0" and "100". However, you forgot the reason phrase. For "100", obviously, the string should be "Trying". Thus, a complete first line of a response should be done with:
osip_message_set_version(response, osip_strdup("SIP/2.0"));
osip_message_set_status_code(response, 100);
//ADD THIS
osip_message_set_reason_phrase (answer, osip_strdup("Trying");
The above will fix the first error, but there looks to be more. You are using "osip_message_get_contact" to retrieve a contact from the response. But there is none. In order to set a contact, you need to search for your IP address, port number, and parameters you want to add. Something like this is advised:
osip_message_set_contact (response, "<sip:192.168.1.10:5678;ob>");
The above API will parse the string as a Contact header and add it to the response.
To make it clear (as you have used it), "response->req_uri" is empty for a response. It means "Request-URI" which is only for request.
If you wish a complete response, you will also need to copy all the "Via" headers:
{
osip_list_iterator_t it;
osip_via_t *via = (osip_via_t *) osip_list_get_first (&request->vias, &it);
while (via != NULL) {
osip_via_t *via2;
i = osip_via_clone (via, &via2);
if (i != 0) {
osip_message_free (response);
return i;
}
osip_list_add (&response->vias, via2, -1);
via = (osip_via_t *) osip_list_get_next (&it);
}
}
NOTE: use osip_strdup instead of strdup for any osip allocation to make your code more portable.
osip_message_to_str should work then!
For more precise code, feel free to have a look at my exosip2 code here. It will certainly help you for the next question you will have!

Assertion Failure in Calculator Program

So I'm working on a simple calculator program to get used to cocoa and objective C. I've redone the whole thing multiple times and every time I finish coding, the first time i build it, it works fine, but every time after that the window wont launch and it gives me these errors:
2013-01-11 10:32:14.760 Visual Caluclator Fix[39892:403] *** Assertion failure in -[NSTextFieldCell _objectValue:forString:errorDescription:], /SourceCache/AppKit/AppKit-1138.47/AppKit.subproj/NSCell.m:1564
2013-01-11 10:32:14.762 Visual Caluclator Fix[39892:403] Ignoring exception raised in __-[NSPersistentUIManager restoreAllPersistentStateWithTalagentWindows:registeringAsReadyWhenDone:completionHandler:]_block_invoke_3: Invalid parameter not satisfying: aString != nil
I've concluded that the problem lies in my textEdited method, because when I comment the code inside of it out, the program has no issues running; however, I have no idea why this is, or why it would run the first time and not any subsequent times. When I put in an exception breakpoint, it points me to the one line in the updateUI method and the call to [self updateUI] in the textEdited method. The following code is the textEdited method and the other methods it references.(I'm fairly sure there's nothing wrong with the solve method because I used it in a command prompt calculator and it worked great. Also, I know this is a pretty convoluted way to program a calculator, with the strings and everything, but I was just trying to integrate the code I already had for the command prompt program into a cocoa program.)
In the AppDelegate class:
- (void)updateUI{
[self.calculationView setStringValue: self.calculation.calcString];//Exception breakpoint points here
}
- (IBAction)textEdited:(id)sender {
self.calculation.calcString = self.calculationView.stringValue;
[self.calculation solve];
[self updateUI];//Exception breakpoint points here
}
In the Calculation class:
- (NSString*)solve{
for (int i = 0; i < [self.calcString length]; i++) {
NSRange nextChar = NSMakeRange(i, 1);
if ([[self.calcString substringWithRange: nextChar] isEqualToString: #"*"]||
[[self.calcString substringWithRange: nextChar] isEqualToString: #"/"])
[self calcTerm: i];
}
for (int i = 0; i < [self.calcString length]; i++) {
NSRange nextChar = NSMakeRange(i, 1);
if ([[self.calcString substringWithRange: nextChar] isEqualToString: #"+"]||
[[self.calcString substringWithRange: nextChar] isEqualToString: #"-"])
[self calcTerm: i];
}
return self.calcString;
}
This might help with your problem:
http://www.raywenderlich.com/10505/my-app-crashed-now-what-part-2
The site explains how assertion errors work and demonstrate how you would fix an error like that.
It sounds to me like something in calcTerm: is setting calcString to nil. Thus, when you retrieve it later to set the field's string value to it, you end up setting the field's string value to nil, which it doesn't like.
You can check this by logging the value of calcString just before the end of solve. Then, start stringing up log statements and/or breakpoints in calcTerm: to find out how you're swapping out your string for nil.

Restricting what is passed into a method

Right lets say I have a method something like :
- (void)doStuff:(NSString *)doStuffWith;
Can I make it so that doStuffWith will only accept certain words like lets say "DoSomething1" and "DoSomething2", so when i call it like :
[self doStuff:#"DoSomething1"];
it will run but if I call it like :
[self doStuff:#"HelloWorld"];
it will give a warning or something?
You should use an enum, like:
typedef enum {
MyStuffOne,
MyStuffTwo,
MyStuffThree
} MyStuff;
- (void)doStuff:(MyStuff)stuff;
thus you will be able to pass only "MyStuff" (MyStuffOne, MyStuffTwo, MyStuffThree)... these are integers and if you want to play with strings, in your method you have to do something like:
NSString *string;
switch (stuff)
{
case MyStuffOne:
string = #"StuffOneString";
break;
default:
...
}
If you need to limit amount of possible values, you should use enumeration data type instead of NSString
Why not just add an if statement into the method like this
- (void)doStuff:(NSString *)doStuffWith{
if([doStuffWith isEqualToString:#"DoSomething1"]){
//do whatever you want here
}else{
//add your warning here
}
}
That should work fine
You could create a method that checks if a word is valid and then assert that method returns true. That would then crash the app if a programmer ever called the method with a bad string, but wouldn't really help if users are able to enter strings themselves. Also, if you use the default project settings, assertions only happen when building with the Debug configuration.
For example:
static NSSet* __validStrings = nil;
- (BOOL)checkString:(NSString*)string
{
if( [string length] == 0 ) return NO;
static dispatch_once_t token;
dispatch_once(&token, ^{
// build the list of valid words once, or load from a plist or something
// if they are very large or change often
NSArray* validWords = [NSArray arrayWithObjects:#"valid", #"doSomething", #"etc.", nil];
__validStrings = [[NSSet alloc] initWithArray:validWords];
});
return [__validStrings containsObject:string];
}
// your doStuff implementation
- (void)doStuff:(NSString*)doStuffWith
{
// This will crash the program and give you debugging information if doStuffWith
// is not in your string list
NSAssert1( [self checkString:doStuffWith], #"invalid string: %#", doStuffWith );
// continue on with your method implementation...
}

Pass a block of code?

Is it possible to pass a block of code, for example:
int i = 0;
while (i < [array count]) {
//Code to pass in here
i++;
}
Reason being that i need to perform various actions on every item in an array at different times, it'd be nice to have 1 method and pass it a block of code to run.
Have you considered using blocks. It's just an idea and not working or compilable code
typedef int (^block_t)();
-(void) methodName:(block_t) code_block
{
int i = 0;
while (i < [array count]) {
code_block() //Code to pass in here
i++;
}
block_t youCode = ^{ NSLog("Just an example"); }
[self methodName:youCode];
You can definitely iterate an array and process a block of code on it. This feature has been a standard part of Objective C since 2.0, iOS since 4.0 and in addition was included in Snow Leopard. If you look up the NSArray class reference you will find the following functions:
enumerateObjectsAtIndexes:options:usingBlock:
Executes a given block using the
objects in the array at the specified
indexes.
enumerateObjectsUsingBlock: Executes a
given block using each object in the
array, starting with the first object
and continuing through the array to
the last object.
enumerateObjectsWithOptions:usingBlock:
Executes a given block using each
object in the array.
You can define the code block to be executed globally in your implementation file, or in place where its needed. You can find some good examples on block programming here: http://thirdcog.eu/pwcblocks/.
It sounds like you want "blocks", which are a feature of Objective-C similar to "lambdas", "anonymous functions" and "closures" in other languages.
See Apple's documentation: Blocks Programming Topics
You should put the code into a method and call the method like so:
-(void)foo{
int i = 0;
while (i < [array count]) {
[self myMethod];
i++;
}
}
-(void)myMethod{
//Code to pass in here
}
You could also store the method as a variable allowing you to change which method is called
SEL methodToCall = #selector(myMethod);
-(void)foo{
int i = 0;
while (i < [array count]){
[self performSelector:methodToCall];
i++;
}
}
-(void)myMethod{
//Code to pass in here
}
first of all you could give a more detailed example.
second you could take a look at Action or Func in case you need a return message (well something equivalent for obj-C if exists)
but again, not understanding what you need to do, it is hard to give you an answer
cause from you Q i could understand as #Trevor did that you need to run a method:
int i = 0;
while (i < [array count]) {
if (i % 2)
EvenMethod(array[i])
else
OddMethod(array[i])
i++;
}
If you can live with 4.0+ compatibility, I highly recommend the use of blocks.
- (void)enumerateObjectsUsingBlock:(void (^)(id obj, NSUInteger idx, BOOL *stop))block
gives you all you need and you can define your block right where you need it. There are some other variants of this, too. Please refer to the 'NSArray' documentation.
Why not just define functions that do what you want, and call them at various times with the items in your array as arguments?
If your concern is that you don't want redundant code with multiple while loops you have here, you could write a function that takes an array and a function as an argument, then applies that function to every element in the array.
Adapted from here:
//------------------------------------------------------------------------------------
// 2.6 How to Pass a Function Pointer
// <pt2Func> is a pointer to a function which returns void and takes an NSObject*
void DoForAllItems( NSArray* array, void (*pt2Func)(NSObject*) )
{
int i = 0;
while (i < [array count]) {
(*pt2Func)([array objectAtIndex:i]);
i++;
}
}
// 'DoIt' takes an NSObject*
void DoIt (NSObject* object){ NSLog(#"DoIt"); }
// execute example code
void Pass_A_Function_Pointer()
{
NSArray* array= [NSArray arrayWithObjects:#"1", #"2", nil];
DoForAllItems(array, &DoIt);
}
http://thirdcog.eu/pwcblocks/#objcblocks
Blocks were added recently to Objective-C I hope they have found their way to the Iphone also.
and it was anwered here also before:
Using Objective-C Blocks
Regards
If you are using Objective C++, I would strongly recommend function objects (even over blocks). They have a nice syntax, are easy to use, and are supported everywhere on modern C++ compilers (MSVC++11, GNUC++11, and LLVMC++11):
void go( function<void (int arg)> func )
{
int i = 0;
while (i < [array count]) {
//Code to pass in here
func( i ) ; // runs func on i
i++;
}
}
calling it:
go( []( int arg ){ // the square brackets are the "capture"
printf( "arg was %d\n", arg ) ; // arg takes on whatever value was passed to it,
// just like a normal C function
} ) ;

Can't return a String value and append it...why?

I am writing an app and am having problems returning a simple string value, and I'm not sure why.
The function I am using (within a file called APIManager.m) is:
- (NSString*) returnVenueUrl {
NSString *venueUrl = [devEnvironment stringByAppendingString:#"venue/id/"];
return venueUrl;
}
I can return this properly by doing this in another .m file:
APIManager *apiManager = [APIManager apiManager];
NSLog(#"view venue URL is here: %#", [apiManager returnVenueUrl]);
But when I go to append a variable cast as a String onto it, I get nothing..
venueURL = [apiManager returnVenueUrl];
venueURL = [venueURL stringByAppendingString:venueId];
NSLog(#"the Full Venue URL is: %", venueURL);
If anyone has any advice on how to fix this, it would be much appreciated!
Use NSMutableString
NSString is immutable (aka non modifiable)