How to Pass multiple objects with "context" in WatchKit - ios

I'm using this following code pass data to my third controller:
[self presentControllerWithName:#"ThirdView" context:MyArray];
The thing is, I would like to pass more than a simple array. I would like to pass a separate string, and another array if possible, and I don't want to add the string or the other array to "MyArray".
Is there a different way of going about this, or do I just restructure this code?

You can create custom object with the data you want to pass or you can bundle the data in the dictionary or array. In swift you can use tuple as well.
This is an example with dictionary:
NSDictionary *myData = #{
#"MainArray" : MyArray,
#"MyString" : #"string",
#"AnotherArray" : anotherArray
};
[self presentControllerWithName:#"ThirdView" context: myData];
Example with Array:
NSArray *myData = #[MyArray, #"string", anotherArray];
[self presentControllerWithName:#"ThirdView" context: myData];

While you could use a dictionary or an array as Greg has suggested, you get no type-safety and you have to ensure that the key names / indexes are the same in both places.
A better approach would be to subclass NSObject and provide a wrapper for the data you are wanting to transfer to that view controller.
Interface:
#interface ThirdViewState : NSObject
#property (nonatomic, copy) NSString *title;
#property (nonatomic, copy) NSArray *list;
#end
Simple empty implementation:
#implementation ThirdViewState
#end
Then you can construct an instance of this object, populate it with data and pass it to the view controller:
ThirdViewState *state = [[ThirdViewState alloc] init];
state.title = #"My 3rd view";
state.list = myArray;
[self presentControllerWithName:#"ThirdView" context:state];
Then in the third view controller's awakeWithContext: method you can pull out the data:
- (void)awakeWithContext:(ThirdViewState *)state {
[super awakeWithContext:state];
// do whatever with state
}

Related

Custom object to NSMutableDictionary

I would like to add a custom object to NSDictionary. It should store three variables: two strings and a boolean.
I read around the net and found NSCoder to be the way but I dislike the result. By using [dictionary setObject:[NSKeyedArchiver archivedDataWithRootObject:customObject]] I end up with NSData information instead of human readable text. My target is to make it readable for human eyes. I do not want to encode the object into binary data.
To make it a little bit more complicated I would like to add my objects inside NSArray. For testing purposes I tried to add NSStrings to NSArray and to invoke [NSDictionary dictionaryWithObject:array forKey:#"myKey"]. The result is perfect. It is readable for human. I would like to add my custom object instead of the NSString.
Desired result should look something like this:
{
TextStrokeColor = "UIDeviceWhiteColorSpace 0.5 1";
TextStrokeWidth = 0;
MyObjects = (
MyCustomObject = {
name = "name";
boooool = 0;
description = "";
}
, ... other objects );
}
What should I use? I do not really get the difference and the use for NSCoder, NSCoding, NSCopying.
I need to be able to edit the text file later on the disk. By having binary representation I cannot. But seems there is no straightforward method.
You can simply use arrays, dictionaries, strings, numbers, dates (anything which can be written into a plist or JSON).
The question is wether this is done solely during 'archiving', or whether your in-memory representation is also arrays and dictionaries. You can also create a custom class which either uses a dictionary internally to store the data and archives / reloads from that dictionary, or the custom class is a standard class with properties and creates a dictionary on-the-fly when archiving or reloading.
Note that when using a keyed archiver, it can support setting the outputFormat to NSPropertyListXMLFormat_v1_0 for some use cases, so once your custom class implements archiving to plist data types you can easily archive the container to a plist (JSON will require more leg work from you to collate the data into true containers).
Have you tried actually creating a custom object by just making a class?
#interface MyCustomClass : NSObject
#property (nonatomic, strong) NSString *name;
#property (nonatomic, strong) BOOL boolValue;
#property (nonatomic, strong) NSString *description;
#end
#implementation MyCustomClass
// put any implementation methods here
#end
Then you can add it to an NSArray or an NSDictionary as you would with any other class.
MyCustomClass *myObject = [MyCustomClass new];
myObject.name = #"name";
myObject.boolValue = YES;
myObject.description #"a description";
[myMutableArray addObject:myObject];
myMutableDictionary[#"some key"] = myObject;

How to declare array in object and store with encode

I am creating a class Ticket. In that ticket I want a mutable array of NSStrings
i.e. in ticket.h
#interface Ticket : NSObject
#property NSString *ticketName;
#property NSMutableArray *games;
However Objective C doesn't allow me to do this. What am I supposed to do to have an array inside an object?
I then want to store that array using encodeWithCoder in the implementation of the object
like i said you might have a syntax problem, there is no reason why Objective-c won't allow you to add an NSMutableArray into your custom objects, try this:
#interface MyObject : NSObject
#property (nonatomic, strong) NSMutableArray *myMutableArray;
//
// .. other properties
//
#end
and in the implementation
#implementation MyObject
- (void)viewDidLoad
{
[super viewDidLoad];
[self.myMutableArray addObject:#"myString1"];
[self.myMutableArray addObject:#"myString2"];
[self.myMutableArray addObject:#"myString3"];
}

Create an array that hold custom class object

I have class, that have several properties, it look like this:
#interface PlaceHolder : NSObject
#property (strong, nonatomic) NSString *name;
#property (strong, nonatomic) NSString *description;
#property (strong, nonatomic) NSString *webPage;
#property (strong, nonatomic) NSNumber *latitude;
What i need is, to create an array, that hold objects of that class. Obvious, properties will not be nil and will be different each time. So, that array must have several hundreds of PlaceHolder object, and it should be possible to get information for any of that object and it properties. But, when i try to create that array, in NSLog i see that it contain only (NULL) objects. This is how i try too add object to array:
In header i wrote:
#property (strong, nonatomic) PlaceHolder *place;
Then:
self.place = [[PlaceHolder alloc]init];
self.place.name = nameString;
NSLog(#"%# name???", self.place.name);
[self.placeObjectsArray addObject:self.place];
self.place.name is not nil, and still, array is empty. Well, its not true, it not empty but, it only contains (null) objects. How to fill array with objects of my class?
Any advice would be appreciated, thanks!
UPDATED:
I init array like this -
-(id)initWithDelegate:(id)delegateObj{
...
self.placeObjectsArray = [NSMutableArray array];
...
return self;
}
UPDATED: Now, when i try to init-alloc array in same method (instead of setting #property and strong relation) i can see it in NSLog. I wonder why it won't happen when i use my array, that set as property..
You need to alloc-init your Mutable Array ;
NSMutableArray *myArray = [[NSMutableArray alloc]initWithObjects:self.place,nil];
or simply
NSMutableArray *myArray = [[NSMutableArray alloc]init];
Then you could add objects with a for loop or whatever you need, using the following :
for ( YOURINSTRUCTION )
{
[myArray addObject:YOUROBJECT]
}
I recommend to lazy instantiate the array, that way it will only get instantiated when really needed. Since you are setting the array as a property, you can override the getter method for it like this:
- (NSMutableArray *)placeObjectsArray
{
if (!_placeObjectsArray) _placeObjectsArray = [[NSMutableArray alloc] init];
return _placeObjectsArray;
}
With this, you can call [self.placeObjectsArray addObject:self.place] anywhere in your code and the array will always be initialized when needed.

Binding NSPopUpButton to an NSArray

I want to populate an NSPopUpButton with an array of NSStrings. I also want to be able to set the selected item in the NSPopUpButton as well as get the selected value. Is there a way to do this using bindings? Here's what I have that only has the content of the array controller bound to arragedObjects.
#interface AppDelegate : NSObject <NSApplicationDelegate>
{
NSMutableArray *myArray;
IBOutlet NSPopUpButton *myPopUpButton;
IBOutlet NSArrayController *processArrayController;
}
#property (assign) IBOutlet NSWindow *window;
#end
#implementation AppDelegate
#synthesize window = _window;
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
NSString *firstObject = #"Lustre";
NSString *secondObject = #"TwoTone Laser";
NSString *thirdObject = #"Laser Mark";
NSString *forthObject = #"Double Lustre";
NSString *fifthObject = #"CG Ink";
// Create the array
myArray = [[NSMutableArray alloc] initWithObjects:firstObject, secondObject,
thirdObject, forthObject, fifthObject, nil];
// Sort the array
[myArray sortUsingSelector:#selector(localizedCaseInsensitiveCompare:)];
// Set contents of the array controller that is bound to the popup button
[processArrayController setContent:myArray];
// Set a selection to an item of the popup button
[myPopUpButton selectItemWithTitle: firstObject];
}
#end
Set up an ivar in your application controller to hold your selection:
#property (copy) NSString *selection;
And of course, synthesize it in your implementation file.
Make these bindings to your NSPopUpButton instance:
Content:
Bind To: Array Controller (unless you've given your array controller another name)
Controller Key: arrangedObjects
Content Values:
Bind To: Array Controller (unless you've given your array controller another name)
Controller Key: arrangedObjects
Model Key Path: (for strings, I've always used 'description')
Selected Object:
Bind To: App Delegate (unless you've given your application delegate another name)
Model Key Path: self.selection
Finally, since your popup button is now bound to selection, this is how you set up your initial selection:
self.selection = firstObject;
Good luck to you in your endeavors.

Accessing an array from another class

I have an array called client in one of my classes and I want to use the information in that array in another class that i have. I have set up the property and synthesized the array in my first class. The code for my first class is
#synthesize client;
...
- (IBAction)testing:(id)sender {
NSString *textContent = myTextView.text;
textContent = [textContent stringByReplacingOccurrencesOfString:#" " withString:#""];
client = [textContent componentsSeparatedByString:#"."];
NSLog(#"%#", client);
}
In my second class I tried importing the h file for my first class and then just accessing the array. The code that I am using is
- (IBAction)ButtonStuff:(id)sender {
ArrayManipulationViewController *myClass = [[ArrayManipulationViewController alloc]init];
NSLog(#"Second Interface");
NSArray *test = myClass.client;
NSLog(#"%#", test);
}
To access object from multiple classes, a common approach is to declare the object in the parent class, and then pass a shared instance of that object to all child classes that require access. For instance, you could declare the array in the AppDelegate, and set array properties in your subclasses, and pass the instance of the array from the AppDelegate to all your subclasses.
Eg: create an NSArray (myArray) in your app delegate, then in the AppDelegate implantation, pass the myArray instance to your sub view controllers using properties.
Or, if you'd prefer; you can declare the array in your first class, and then pass the array instance from your first class to your second class using properties. Then, any changes made in your second class will be available in your first class, since the INSTANCE is the same.
UPDATED ANSWER:
For the second approach, you're best declaring the array in your first class implementation, and then when you instantiate the second class, pass the instance of the array to the second class using properties. In this example, you'll need to have an NSArray property in your second class to be able to pass the array over to it using [secondClassInstance setClient: client];
Your second class interface might look like this:
#interface SecondClass : NSObject
{
NSArray *client;
}
#property (nonatomic, retain) NSArray *client; // don't forget to synthesize
#end
Then, in your first class, you can do the following to pass over your instance of the array:
NSArray *client = [[NSArray alloc] initWithObjects:#"Object 1", #"Object 2"];
//...
SecondClass *secondClass = [[SecondClass alloc] init];
[secondClass setClient: client]; // passing the original client instance here
// don't forget to release secondClass instance when finished

Resources