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.
Related
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
}
I have 2 Interface Controllers in my WatchKit. The first one is called InterfaceController while the other is called DetailsForWatch. IC has a tableView on it. It parses data from a Parse class, and displays data from each entry in the class as a row. This works fine.
What I am trying to do is pass the PFObject for the selected row to a PFObject in DetailsForWatch. My setup for DFW is:
.h
#interface DetailsForWatch : WKInterfaceController {
}
#property (nonatomic, retain) IBOutlet WKInterfaceLabel *detailsLabel;
#property (nonatomic, retain) PFObject *finalObject;
#end
.m
- (void)awakeWithContext:(id)context {
[super awakeWithContext:context];
NSString *details = self.finalObject [#"Request"];
[self.detailsLabel setText:details];
NSLog(#"%#", self.finalObject);
// Configure interface objects here.
}
In IC, for .h I have:
#class DetailsForWatch;
#interface InterfaceController : WKInterfaceController {
DetailsForWatch *_theDetails;
}
#property (retain) DetailsForWatch *theDetails;
#end
In the .m I have:
#synthesize theDetails = _theDetails;
for didSelectRowAtIndex, I have:
_theObject = _theObjective[rowIndex];
self.theDetails = [[DetailsForWatch alloc] init];
_theDetails.finalObject = _theObject;
I set up the DFW as a Push selection from the Group on IC. When I select a row in the IC, it pushes a blank screen, and the NSLog shows that the PFObject named finalObject is (null). What am I doing wrong that it is not passing on PFObject properly?
There are a couple of ways to pass data between the two interface controllers. The way I have been doing it is like this:
create a segue (give it an identifier if necessary) between the two controllers in my storyboard.
In interface controller 1 implement
- (id)contextForSegueWithIdentifier:(NSString *)segueIdentifier
it will be called when the segue is triggered via button press or whatever.
This can return any object such as a dictionary of the data (in your case 'theDetails')
In interface controller 2 implement
- (void)awakeWithContext:(id)context
the context object here will be the one you passed through in controller 1
I have an NSMutableArray declared as property in .h and initialized in viewDidLoad in my SPOCVC .m (UIViewController)...
#property (strong, nonatomic) NSMutableArray* SPOCTrackList;
in viewDidLoad
if ([self SPOCTrackList] == nil) {
self.SPOCTrackList = [[NSMutableArray alloc]init];
NSLog(#"SPOTTrackList INITIALIZED");
}
In a separate VC, I'm trying to pass/addObject to SPOCTracklist...
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
SCTrack* selectedTrack = self.trackList[indexPath.row];
[[[SPOCVC sharedInstance]SPOCTrackList]addObject:selectedTrack];
NSLog(#"%lu", (unsigned long)[[[SPOCVC sharedInstance]SPOCTrackList]count]);
So my NSMutableArray is initialized and I can add dummy objects, but why can't I pass it from another VC using singleton or anything, such as...
SPOCVC* spocVC = self.tabBarController.viewControllers[2];
[spocVC.SPOCTrackList addObject:selectedTrack];
Thanks for pointing me in the right direction.
View controllers are only intended to be around while they are on screen. They are not a place to store data. Generally when one view controller talks directly to another view controller that it didn't create, you're doing something wrong.
Move SPOCTrackList to your model and have both view controllers talk to it rather than to each other.
There should never be a "sharedInstance" on a view controller. That's a sure sign that you're abusing the view controller as the model.
What's probably happening in your particular case is that viewDidLoad is running on a completely different SPOCVC than your sharedInstance.
why not use appdelegate to handle this
appdelegate.h
//add property to hold the reference
#property (nonatomic, copy) NSMutableArray *referenceArray;
//share the app delegate
+(AppDelegate *)sharedAppDelegate;
#end
in appdelegate.m
//synthesize the property
#synthesize referenceArray;
//return the actual delegate
+(AppDelegate *)sharedAppDelegate {return (AppDelegate *)[UIApplication sharedApplication].delegate;}
in viewdidload method
//add the delegate
import "appdelegate.h"
//init the array
self.SPOCTrackList = [[NSMutableArray alloc]init];
//Add reference
[AppDelegate sharedAppDelegate].referenceArray = self.SPOCTrackList;
and add anywhere like this
import "appdelegate.h"
[[AppDelegate sharedAppDelegate].referenceArray addobject: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.
I created an Xcode app which stores user input using the core data framework in this case reviews (detail and rating 0-5).
So basically I have managed to create a view controller which stores the user inputs and then displays it in a table view controller.
Users are able to then choose any existing reviews they want from the table view controller, which then takes them to a new view controller which displays that specific review the user chose.
The problem is that I have managed to display the string value using this code "[self.detailView setText:[self.managedObject valueForKey:#"detail"]];" but I cannot get it to display the rating value which is stored as integer(16) in the core data.
.h detail view controller
#import <UIKit/UIKit.h>
#import "reviewTableViewController.h"
#import "reviewViewController.h"
#import "Reviews.h"
#interface reviewDetailViewController : UIViewController <NSFetchedResultsControllerDelegate, UITextFieldDelegate> //adding fetched controller delegate and text field delegate
#property (strong, nonatomic) NSManagedObjectContext *managedObjectContext;
#property (strong, nonatomic) IBOutlet UITextView *detailView; //holds detail values
#property (nonatomic, strong) Reviews *reviews; //property for holding reviews
#property (strong) NSManagedObject *managedObject; //hold core data property
#property (strong, nonatomic) IBOutlet UILabel *ratingView; //holds rating values
#property (strong, nonatomic) IBOutlet UIButton *myButton;
#property (strong, nonatomic) IBOutlet UIButton *myButton1; //buttons for borders
#end
.m detail view controller
- (void)viewDidLoad
{
[super viewDidLoad];
_myButton.layer.borderWidth = .5f;
_myButton.layer.borderColor = [[UIColor lightGrayColor]CGColor]; //adding borders for tet displa using buttons, when screen loads
_myButton1.layer.borderWidth = .5f;
_myButton1.layer.borderColor = [[UIColor lightGrayColor]CGColor];
[self.detailView setText:[self.managedObject valueForKey:#"detail"]]; //displaying detail value
//[self.ratingView setText:[self.managedObject valueForKey:#"rating"]];
//[self.ratingView setValue:[NSNumber numberWithInteger:managedObject] forKey:#"rating"];//displaying rating value
//[self.puzzle setValue:[NSNumber numberWithInt:timeTaken] forKey:#"bestTime"];
}
.m table view controller
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
// Get a reference to our detail view
// Pass the managed object context to the destination view controller
// [super prepareForSegue:segue sender:sender];
// If we are editing a picture we need to pass some stuff, so check the segue title first
if ([[segue identifier] isEqualToString:#"detailSegue"]) //using segue link name given
{
//Get the row we selected to view
NSManagedObject *managedObjects = [self.reviewsArray objectAtIndex:[[self.tableView indexPathForSelectedRow] row]]; //choosing the selected cell value
reviewDetailViewController *destViewController = segue.destinationViewController;
destViewController.managedObject = managedObjects; //displaying it in the destination controller
}
}
You need to convert the integer into a string.
[self.ratingView setText:[NSString stringWithFormat:#"%#", [self.managedObject valueForKey:#"rating"]]];
NSNumber *x = managedObject.rating; // rating is NSNumber!
int y = x.intValue; // this is how you get an int!
label.text = [NSString stringWithFormat:#"%i", managedObject.rating.intValue];