organize data model objective c - objective-c

I have this visual part in my app. I've attached file below:
There are next user interface controls:
First UIScrollView (_blueScrollView) is located on main view of UIViewController that can contain many other views each one is called _magentaView...
Each _magentaView contains UIView (_labelView...) for storing UILabel objects. So there is some struct like UITableView in UITableView.
In my case all objects have UIViewController class.
I need to get access to all my labels that are storing in labelsViews. I need to get value of property text of those objects.
So if I make in standard case this will looks like this
for (UIViewController *magentaVC in scrollViewObjects) {
for (UIViewController *labelVC in magentaObjects) {
and get my UILabel objects here.
}
}
but as I think this is incorrect. Because I need to use data model for this instead to use UIViewController objects. What do you think about this and which way do I need to choose?

This is exactly the job for a UITableView. The table itself has a scroll view embedded in it; magentaView 1 and 2 would be sections of the table, and the labelViews would be table view cells.

Related

Override a property to make it read-only from the subclass

I would like to subclass UILabel in such a way that the user of the class cannot set the text directly through label.text = #"foo". Instead I'd like to set the text from inside the subclass depending on some values.
What I tried:
BalanceLabel.h:
#interface BalanceLabel : UILabel
#property(nonatomic,copy, readonly) NSString *text;
#end
However, I get a warning telling me I'm restricting text access (like I wanted to) but I don't get any compile time errors if I try to set the text directly using an object of my subclass.
You can't do this. As a trivial example as to why not, just think of how the following code should behave:
UILabel *label = [[BalanceLabel alloc] init];
label.text = #"string";
That code creates a BalanceLabel, but stores it in a variable of type UILabel, which means that the subsequent setting of the .text property can't know that you tried to make the property readonly in BalanceLabel.
Unfortunately there's not much you can do about this. You could override the setter to throw an exception, which will let users know what they did wrong, but of course will also crash the app.
You should be putting the logic into controller that managed the view instead of view directly.
I assume you have some view that gets updated with new values and you want to update the BalanceLabel based on these new values.
Your controller is a delegate for your view so it receives new values, from either user or other modules of your app that populated new values (like loaded from file, downloaded from network and so on).
Your controller then figures out which bits of view needs update and sets new values - in your case calculate balance, I assume

How do I determine the row in NSTableView that represents a specific object instance?

I have a NSTableView driven by NSManagedObject/CoreData and a custom graph view on the same form which plots each row on a X/Y grid based on some derived calculations. Each point on the graph view causes and event to run a (SEL)Selector on my window controller..
And I am stuck ! I want to be able to change the selection in the NSTableView to be the object selected and returned by the graph view. ie. use the graph to change the selection/row in the NSTableView list.
I have a method as follows:
-(void)setSelectedOpportunity:(Opportunity *)opty
{
_selectedOpportunity = opty;
[_opportunityTable selectRowIndexes:???? byExtendingSelection:NO];
}
_opportunityTable is an NSTableView that gets is content from and NSArrayController called _opportunityAC. This array controller gets its data from a NSManagedObjectContext containing NSManaged objects called Opportunity.
Can anyone tell me how do I determine the row in the table that represents the object opty.
Thanks
Ian

Initialise components with custom names

I have a view that contains 15 images and labels .
I ve put them all on view but in some cases I don t want to show them all .
For example I have
IBOutlet UIImageView* image1 ;
....................* image2 ;
......................
.....................*imagen;
I have a list with objects but if i don t have n objects and i have just m i don t want to show images from m to n.
In for loop I would like to have something
- > string componentToShow = "image" + i ;
and now (componentToShow).....set to visible and diffrent prop .
Thanks,
Raluca
If I understand you correctly, you've got a varying number of objects, and you want to display accompanying views for the objects you have. You have laid out the maximum number of accompanying views in a nib file, and are now struggling with hiding the ones you don't want. Is that correct?
I would do it like this:
Take the accompanying views out of the nib. Create a second nib that represents a single object (e.g. label and image together). In your view controller's viewDidLoad method, load the nib representing an object and store it in an instance variable. When an event happens that creates a new object, instantiate the nib and add the views produced to your view controller's view hierarchy.
Alternatively, if your representation of objects is simple enough, skip the second nib, and simply create the views directly in code.

Target Action data source update for view based NSTableView

I have situation where I use view based Table Views and don't want to use bindings between data source and table view. This is mainly due to the fact that my NSTableCellView can have multiple subviews, complex validation and triggered calls to methods in other objects.
We have very clear path of updating NSTableView with data source with:
tableView:viewForTableColumn:row:
However, for backwards, that is updating datasource with updates in NSTableView we have nothing of the sort we have for cell based Table views:
tableView:setObjectValue:forTableColumn:row:
Target Action pattern is suggested instead. So, I have basically 2 questions:
If I set target and action for one specific view, or its subview, how do I get proper row and column info to know what to update in data source?
Should clickedRow and clickedColumn from NSTableView do the trick, although I have edited or changed one subview object?
How can I inform the target (as other object, not NSTableView instance) about row and column if action will pass for example NSTextField as parameter?
I can basically come to clickedColumn and clickedRow (if those 2 properties are proper answer to first question) through subview tree, but I find this as pretty much non-elegant solution and have hunch there is a better way....
THanks in advance....
NSTableCellView has an objectValue. Presumably you're already setting it, so the action can use [(NSTableCellView *)[sender superview] objectValue] to find out which object it needs to manipulate.
I suggest that you also subclass NSTableCellView and implement the action there. If you need access to other parts of the model, you can add an outlet for your view controller.
If you really need the row number, you can call indexOfObject on your content array.
The two NSTableView Methods rowForView and columnForView should do the trick.
You can call them with the sender of an Target/Action Method, like one triggered by an NSButton in your TableView (its ok, to have it somewhere in a subwiew)
Or you can call these Methods from within a delegate method implementation like the textDidChange from NSTextDelegate. So you can easily update your corresponding Array.
If you don't want continous updates textDidEndEditing would also do the job.
- (void)textDidChange:(NSNotification *)notification
{
NSTextView *tv = [notification object];
int r = [tableView rowForView:tv];
int c = [tableView columnForView:tv];
NSLog(#"Row: %d Column: %d", r, c);
// updating code here
}

Populating NSTableview from a mutable array

I've been attempting this for two days, and constantly running into dead ends.
I've been through Aaron Hillegass's Cocoa Programming for MAC OS X, and done all the relevant exercises dealing with NSTableview and mutable arrays, and I have been attempting to modify them to suit my needs.
However none of them seem to be using an array with objects as a data source, it seems to use the tableview as the datasource.
I'm trying to implement Jonas Jongejan's "reworking" of my code here, with a Cocoa front end to display the results.
Any pointers or suggestions I know this should be simple, but I'm lost in the wilderness here.
I can populate the table by setting the array
It's pretty simple really, once you get to understand it (of course!). You can't use an NSArray directly as a table source. You need to either create a custom object that implements NSTableViewDataSource or implement that protocol in some existing class - usually a controller. If you use Xcode to create a standard document based application, the document controller class - (it will be called MyDocument) is a good class to use.
You need to implement at least these two methods:
– numberOfRowsInTableView:
– tableView:objectValueForTableColumn:row:
If you have a mutable array whose values you'd like to use in a table view with one column, something like the following should do as a start:
– numberOfRowsInTableView: (NSTableView*) aTableView
{
return [myMutableArray count];
}
– tableView: (NSTableView*) aTableView objectValueForTableColumn: (NSTableColumn *)aTableColum row: (NSInteger)rowIndex
{
return [myMutableArray objectAtIndex: rowIndex];
}
It has just occurred to me that you could add the above two methods as a category to NSArray replacing myMutableArray with self and then you can use an array as a data source.
Anyway, with a mutable array, it is important that any time you change it, you need to let the table view know it has been changed, so you need to send the table view -reloadData.
If your table view has more than one column and you want to populate it with properties of objects in your array, there's a trick you can do to make it easier for yourself. Let's say the objects in your array are instances of a class called Person with two methods defined:
-(NSString*) givenName;
-(NSString*) familyName;
and you want your table view to have a column for each of those, you can set the identifier property of each column to the name of the property in Person that that column displays and use something like the following:
– tableView: (NSTableView*) aTableView objectValueForTableColumn: (NSTableColumn *)aTableColum row: (NSInteger)rowIndex
{
Person* item = [myMutableArray objectAtIndex: rowIndex];
return [item valueForKey: [tableColumn identifier]];
}
If you replace valueForKey: with valueForKeyPath: and your Person class also has the following methods:
-(Person*) mother;
-(Person*) father;
-(NSString*) fullName; // concatenation of given name and family name
you can add table columns with identifiers like: father.fullName or mother.familyName and the values will be automatically populated.
You could go the datasource route and do all of the heavy lifting yourself, or you could let bindings do all the heavy lifting for you. Add an NSArrayController to the nib file that has the table view in it. Make sure that the File's Owner of the nib is set to the same class that has the mutable array in it. Bind the contentArray of the array controller to File's Owner.myMutableArray. For each column bind Value to the array controller arrangedObjects and add the appropriate key path. This will allow you to get things like user sorting for free if you ever need it.
On the iPhone (I know you're talking about Mac, but maybe this could help) you have to use delegation for loading a tableView. It asks for a cell and you use your array to fill-in the data where needed.
I'm not sure if this works for the Mac, but it'd be worth looking into.
Maybe set dataSource to self and use those delegate methods to access your array based on the row and column #
Apple has a whole guide for Table View Programming so I suggest you start with the Using a Table Data Source section of the that guide.