Three20 Passing of Object - iphone

i would like to know that after passing object from view to view with URL, how to i pass it to the model
so i can use it for web service and populate the datasource.
Using Three20 (:
Thanks.

Copied from: http://three20.info/article/2010-10-06-URL-Based-Navigation
Original Author: Jeff Verkoeyen
One of the first questions people ask about TTNavigator is how to pass native objects around, rather than encoding them somehow in a URL. There is a simple pattern for this, using the query property of TTURLAction (or its equivalent convenience function, applyQuery:). For example, imagine you wanted to pass along an NSArray of items to show in the new view:
NSArray *arr = [...load up with data...];
[[TTNavigator navigator] openURLAction:[[TTURLAction actionWithURLPath:#"tt://restaurant/Chotchkie's"]
applyQuery:[NSDictionary dictionaryWithObject:arr forKey:#"arrayData"]]];
In this example, the array is passed directly to the initWithName: but only if there is a matching selector that accepts the query:
-(id) initWithName: (NSString*)name query:(NSDictionary*)query {
for (MyObject* item in [query objectForKey:#"arrayData"])
//... do something with item ...
}
// ...
}

Related

What is the role of selector in UILocalizedIndexedCollation's sectionForObject:(id)object collationStringSelector:(SEL)selector method

I am a beginner of iOS development and while going through this document (iOS Developer Guide about configuring a TableView with Indexed List) I came across this:
// Listing 4.7
for (State *theState in statesTemp) {
NSInteger sect = [theCollation sectionForObject:theState collationStringSelector:#selector(name)];
theState.sectionNumber = sect;
}
I could not figure out the selector (#selector(name)) and its purpose, nor could I find the method with the name passed in the selector i.e. name. I googled for examples to find a better explanation, and came across this example.
In the code listing, there is a statement which is a method call:
    
self.tableData = [self partitionObjects:objects collationStringSelector:#selector(title)];
now the selector is called title. I have not been able to find a better explanation, and my question is what is the purpose of this selector and the method referred by this selector, and what should it do and return.
In general
With the #selector(title:) you define which method will be called.
in my example it will call
- (void) title:(id)someObject {}
Be carefull with the semicolon at the end! If you have a semicolon at the end you method will have parameters like mine above.
Your code states just #selector(title) and will call a method title without a parameter like this:
- (void)title {}
Specific to UILocalizedIndexCollation
The docs state:
selector
A selector that identifies a method returning an identifying
string for object that is used in collation. The method should take no
arguments and return an NSString object. For example, this could be a
name property on the object.
So i would suggest you implement it like this
self.tableData = [self partitionObjects:objects collationStringSelector:#selector(title)];
...
- (NSString *)title {
NSString *title;
// some code to fill title with an identifier for your object
return title;
}
Try replace the title with self:
self.tableData = [self partitionObjects:objects collationStringSelector:#selector(self)];
worked for me

for loops - Object type disregarded?

I sometimes like to organize IB elements into NSArrays primarily to help me organize my elements. Most often, different classes of objects make it into the same array with each other. While this is a convenient way of organization, I can't seem to wrap my head around why if I have an array like this:
NSArray *array = [NSArray arrayWithObjects:((UITextField *)textField), ((UISegmentedController *)segmentedController), nil];
Why I get "Does not respond to selector" messages when I put a for loop like this:
for (UITextField *text in array) {
[text setText:#""];
}
The for loop seems to be passed objects that are not of class UITextField.
What is the point of declaring the object's class if all objects in the specified array are passed through the loop?
EDIT Just for reference, this is how I'm handling it as of now:
for (id *object in array) {
if ([object isMemberOfClass:[UITextField class]]) {
foo();
} else if ([object isMemberOfClass:[UISegmentedController class]) {
bar();
}
}
When you do
for (UITextField *text in...
the object pointers from the array are cast to UITextField* type - so if the object isn't actually a UITextField, all sorts of weird things may happen if you try to call UITextField methods.
So instead use the id type (no * needed, btw):
for (id obj in array)
Then check the type as you do and call the appropriate methods. Or, filter the array to get only objects of a certain type, then go though that type only:
for (UITextField* text in [array filteredArrayUsingPredicate:...])
Edit: here's how to build class filter predicates:
Is it possible to filter an NSArray by class?
What is the point of declaring the object's class if all objects in the specified array are passed through the loop?
The class name is just there to let the compiler know what it should expect to find. This allows it to try to figure out what methods it should expect you to call and how you might treat the object. It's the same idea as passing in an int to a method that takes float. The method will not ignore ints - it's assuming you're passing the correct type. You're just giving this construct a little more credit than it's due:
for (UITextField *text in array)
It just doesn't have that functionality. How you're handling it now is the correct way.
Are you sure you don't get an error when you run that code? The "does not respond to selector" message is a runtime error, not a compile time error. The compiler has no idea whether the objects in the array implement -setText:, but you should certainly get an error when you actually send that message to an instance of UISegmentedControl.
Another possibility is that you've got a class called UISegmentedController that does have a -setText: method. The name of the class that implements the multi-part bar-graph-looking user interface widget is UISegmentedControl. So either the code you're showing isn't real, tested code, or you've got a class that we don't know about.

Objective-C: Share object between two view controllers

I have an iPhone application and I do this in my MyView1Controller:
MyView2Controller *myV2C = [[MyView2Controller alloc] initWithNibName:#"MyView2" bundle:nil];
myV2C.shareObject = self.shareObject;
[self.navigationController pushViewController:myV2C animated:YES];
[myV2C release];
So I push shareObject to the next ViewController. There, in viewDidLoad, I set a property of shareObject like this:
self.shareObject.myText = #"Test String";
So in MyView2Controller, everything is okay, the String is set. But going back to the previous MyView1Controller with the left upper "back" Button, the value of shareObject.myText is not set to Test String.
So, how can I do this? I want to give the View2Controller an object which can be modified, and the modifications I want to have in the View1Controller.
Does anyone know? Thank you in advance & Best Regards, Tim.
OR you can even try using the Singleton pattern
http://www.cocoadev.com/index.pl?SingletonDesignPattern
You can use delegation pattern and/or key value observations
EDIT:
You can achieve this my creating a single object, and then use that object in all classes, wherever you want. For this you can use singleton class, Or you can create a class method. For ex:If I have class A, and I want to push some values in B class, So if I modify the values in B, the newly updated value can be retrieved in a too, or in any other class. In that case, you can create a different class (usually subclass of NSObject),and then write the getter/settor methods in that.
Suppose the name of this newly created class is Manager, then in Manager. m create getter/setter methods, like
NSString *strGlobal;
+(void)setString:(NSString *)strTemp
{
if(!strGlobal)
{
strGlobal = [[NSString alloc] init];
}
//point to same location
strGlobal = strTemp;
}
+(NSString *)getMySavedString
{
return strGlobal;
}
Now In you class A , where you want to send the value to Class B controller, call the setter method to set the value, like: -
-(void)navigateto_ClassB
{
//Setting the value, that should be sent to the other controller
[ManagerClass setString:#"Hello"];
[self.navigationController pushViewController:[[[ClassB alloc]init] autorelease] animated:YES];
}
Now In class B (Or wherever you want to get the saved value, use getter method, like:-
NSString *strSavedValue = [ManagerClass getMySavedString];
No you will have the value, If you want to update the value from anywhere, the again call the setter method, with new value. For ex, i want to update the value in class B, then
[ManagerClass setString:#"Hello Upadted"];
Now this value is updated to same memory location, retrieve it from anywhere using getter method created in Manager class.
As I stated earlier, this is the easiest but not the best approach. Alternatively, you can achieve same functionality with delegate patterns, KVOs (Key value observations) and/or singleton class.
tia was right: "You did it right already, so there must be something wrong somewhere".
It was my fault, so the source code in my question is correct.

copying object from NSMutableArray to another using IF statement

OK, maybe I'm not seeing clear anymore and hope you can help.
I'm trying to select an Object from a NSMutableArray using:
if([car.seat isEqualToString:#"fancyOne"]){
fancyThings = [[NSMUtableArray]init];
[fancyThings addObjects: car];
}
Now I forgot to tell you I'm new at this Objective-C, so maybe I'm thinking the wrong way.
What I'm basically trying to do is to get an Object from one array by selecting a value of it's components.
This is the way to do it, I am however keep having trouble with my if-statement.
If I leave out the IF-statement it does fill my other NSMutableArray with the exact same object (thisCar) but if I put in the IF-statement it doesn't pick up that the string is the same in thisCar.seat.
I next example it puts everything in the normalThings but there are some aCar.seats which contain the string FANCYONE. I checked the XML file on spaces and that sort of things but everything is in order as far as I can see.
Shall I build it using NSScanner instead of IsEqualToString?
- (void)viewDidLoad {
appDelegate = (XMLAppDelegate *)[[UIApplication sharedApplication] delegate];
appDelegate.fancyThings = [[NSMutableArray alloc]init];
for (CARS *aCar in appDelegate.someCars) {
if ([aCar.seats isEqualToString:#"FANCYONE"]){
[appDelegate.fancyThings addObject:aCar];
}
else {
[appDelegate.normalThings addObject:aCar];
}
}
self.title = #"Cars";
super viewDidLoad];
}
EDIT:
My BAD!! The code supplied was in fact in order!
There was a mistake in my XMLParser, which added blank lines to the strings, so I couldn't get an equal string!
Hopefully this will give you some guidance:
//init new array
NSMutableArray *fancyThings = [[NSMutableArray alloc] init];
//walk your array
for (SomeCarObject *thisCar in arrayOfCars) {
//is thisCar a qualifying object
if ([thisCar.seat isEqualToString:#"fancyOne"]) {
//yes, add thisCar object
[fancyThings addObject:thisCar];
}
}
You'll want to create that NSMutableArray outside of the for loop (assuming you're iterating through a collection). Then you can add to that NSMutableArray like you did.
Hope this helps!
BTW, you should edit your question with the comment you made to elaborate on it..
It's depends from volume of objects, which u deal with. If there is 1000 objects or less, this method looks good. But if there is more objects, u have risk to freeze u application and have a big memory leaks.
Also if u will need concurrency code later, u have to keep in u mind some
other solutions.
U can using not just a string objects in u array, u can try to fill u array after application startup in objects, which response if string is same or not. Or using nsdictionary with appropriate keys.
Please read my post multithread search design

PhoneGap.exec() passing objects between JS and Obj-C

The only way I found to passing objects between the JS and Obj-C it's by encoding the JS object by using JSON.stringify() and pass the json string to PhoneGap.exec
PhoneGap.exec('Alarm.update',JSON.stringify(list));
... and rebuild the object in Obj-C:
NSString *jsonStr = [arguments objectAtIndex:0];
jsonStr = [jsonStr stringByReplacingOccurrencesOfString:#"\\\"" withString:#"\""];
jsonStr = [NSString stringWithFormat:#"[%#]",jsonStr];
NSObject *arg = [jsonStr JSONValue];
It's that correct ? there is a better/proper/official way for doing this ?
PhoneGap.exec was designed for simple types. Your way is ok, alternately you can just pass your single object in (would only work for a single object only, see footer about how we marshal the command), and it should be in the options dictionary for the command. Then on the Objective-C side, use key-value coding to automatically populate your custom object with the dictionary.
e.g.
MyCustomObject* blah = [MyCustomObject new];
[blah setValuesForKeysWithDictionary:options];
If you are interested in how PhoneGap.exec works, read on...
* --------- *
For PhoneGap.exec, the javascript arguments are marshaled into a URL.
For the JS command:
PhoneGap.exec('MyPlugin.command', 'foo', 'bar', 'baz', { mykey1: 'myvalue1', mykey2: 'myvalue2' });
The resulting command url is:
gap://MyPlugin.myCommand/foo/bar/baz/?mykey1=myvalue1&mykey2=myvalue2
This will be handled and converted on the Objective-C side. foo, bar, baz are put in the arguments array, and the query parameters are put in the options dictionary. It will look for a class called 'MyPlugin' and will call the selector 'myCommand' with the arguments array and options dictionary as parameters.
For further info, see phonegap.js, look at PhoneGap.run_command
I think this is the best way to do it, if not the only way.
The PhoneGap.exec call just takes a NSDictionary of objects under the covers so I don't see of a better way to handle it.
most methods are structured like
- (void)someMethod:(NSArray*)arguments withDict:(NSDictionary*)options {
}