I think the biggest problem I'm having with understanding programming is understanding what a particular method does. For example
- (BOOL)tableView:(NSTableView *)aTableView shouldEditTableColumn:(NSTableColumn *)aTableColumn row:(NSInteger)rowIndex
When I look at the above method I know that it returns a boolean and that the method receives the following.
NSTableView
NSTableColumn
NSInteger
However, I don't understand what I need to provide to use the method correctly.
Do I just return a boolean?
It comes down to a saying: code tells you how, comments tell you why.
If you are writing a method, you need to know why you want the method and document it accordingly, a.k.a. comments. If you are overriding a method, then you would hope the producer of the method would document about what the method does.
If you're diving into iPhone development without a bit of programming background, you should at least read up the Introduction to The Objective-C Programming Language. If you want to find out what a particular method does in your code, you can always right click the method name and choose "Find Text in Documentation" to read more about it.
This method will be called by the table (or something) on your delegate (the class you are implementing this method in) when the table needs to know if a certain row and column can be edited. You just need to return YES or NO to indicate if you want to let it be edited.
This is an example implementation:
-(BOOL)tableView:(NSTableView *)aTableView shouldEditTableColumn:(NSTableColumn *)aTableColumn row:(NSInteger)rowIndex {
return NO;
}
This will mean the table can never be edited.
A more complex implementation like this would let only the first row be editable:
-(BOOL)tableView:(NSTableView *)aTableView shouldEditTableColumn:(NSTableColumn *)aTableColumn row:(NSInteger)rowIndex {
if (rowIndex == 0)
return YES;
else
return NO;
//This can be shortened to:
//return rowIndex == 0;
}
The name of the method tableView:shouldEditTableColumn:row: should give you a clue that it is about editing rows and columns in a table view. You could probably guess that, since it is returning a boolean it's called to determine with a table view should edit the supplied row of the supplied column. However, that would just be a guess, so at this point (if I hadn't been using that method only yesterday and thus know exactly what it is for) I would start googling for it (or using Xcode search if I had access to Xcode).
A useful tip for Googling Cocoa documentation is to search only on site:developer.apple.com so we'll try site:developer.apple.com tableView:shouldEditTableColumn:row:. The top hit in this case is NSTableViewDelegate which is the one we want.
Related
I have two NSTableViews on screen; I just want to drag a row from one table to the other table. I see lots of tips here and there but I do not see a complete example and I'm a bit confused. I saw examples that were totally different to Apples sample apps TableView playground and drag and drop outlineView.
I decided to use Apples method, but now im stuck. TableView playground implement these methods in their model object.
- (NSArray *)writableTypesForPasteboard:(NSPasteboard *)pasteboard
- (id)pasteboardPropertyListForType:(NSString *)type
- (NSPasteboardWritingOptions)writingOptionsForType:(NSString *)type pasteboard:(NSPasteboard *)pasteboard
I dont understand how to set these up. For the 1st method i returned an array with string #"com.mycompany.myapp.mypasteboardtype"as suggested in this question.
What should i put for the 2nd method? My model is a custom object that has a number of strings, Arrays, and dictionary variables. I also do not understand the 3rd method. I wish there was some example i could see that does a simple drag from one table to another with a custom model object.
EDIT: My implementation based on response below
-(id)pasteboardPropertyListForType:(NSString *)type {
return [NSKeyedArchiver archivedDataWithRootObject:self];
}
-(NSArray *)writableTypesForPasteboard:(NSPasteboard *)pasteboard {
return [NSArray arrayWithObject:myDragType];
}
// Other methods that need to be implemented
-(id)initWithPasteboardPropertyList:(id)propertyList ofType:(NSString *)type {
return [NSKeyedUnarchiver unarchiveObjectWithData:propertyList];
}
+(NSArray *)readableTypesForPasteboard:(NSPasteboard *)pasteboard {
return [NSArray arrayWithObject:myDragType];
}
// And finally your object needs comply with NSCoder protocol. These following 2 methods needs to go in the object model associated with a row.
-(void)encodeWithCoder:(NSCoder *)aCoder {
[aCoder encodeObject:oneOfMyIvarsToEncode forKey:#"someKey"];
}
-(id)initWithCoder:(NSCoder *)aDecoder {
self = [super init];
if (self) {
oneOfMyEndodedIvars = [aDecoder decodeObjectForKey:#"someKey"];
}
return self;
}
What should i put for [pasteboardPropertyListForType:]? My model is a custom object that has a number of strings, Arrays, and dictionary variables.
It depends on what type you're being asked for.
If it's your own custom type that you made up, you can put whatever you want. Really—if it's your type that you've invented, you can return whatever you want here, as long as it's a valid property list. You just have to make sure that your paste/drop code (pasteboard reading) is expecting the same stuff.
If you want to support internal drags (reordering and/or relocation within the hierarchy), you should have at least one custom type that identifies the object so that you can look up the same object when accepting the drop (in order to move it rather than duplicate it). For a Core Data object, you might use the absolute string of the object's identifying URI.
If you want to support dragging to other applications, you should have at least one non-custom type that those other applications will recognize. What type(s) you support will depend on what your model represents: if they're images (or recipes for creating them, such as stacks of layers), you could support PNG, TIFF, JPEG, etc.; if they're contacts, you could support vCard; if they're text, you could support plain text and/or RTF and/or HTML and/or WebArchive and/or Microsoft Word; etc.
You return an array of the types that this object can be turned into from writableTypesForPasteboard:; afterward, pasteboardPropertyListForType: must look at what type it was asked for and return a property list of that type.
For most external formats, pasteboardPropertyListForType: must return a data object. For your own custom formats, it's usually either a dictionary or an array of dictionaries, although, as I said, the only real requirements are that it must be a plist of some sort and your reading code must be able to understand it.
I also do not understand [writingOptionsForType:pasteboard:].
You must return a bit mask indicating when and how you will write the type to the pasteboard. The available options are documented.
Currently, there's only one: You can promise the data. This means that the pasteboard will not immediately ask you for the data; it will wait until the user pastes or drops it somewhere (or the data is otherwise requested by any application—e.g., a poorly-written drop validation method could request the data and examine it during validation, rather than drop acceptance). Only then will it call pasteboardPropertyListForType: for that type. (And this is a per-type option; you can choose to promise some types but not others.)
Promising is great for data that is expensive to compute and/or store; for example, a compressed archive (compute) or a large image (store).
Does it make sense logically to have two data sources populating a single NSTableView? Or would a pop up button (with ability to choose from which data source to read)be more reasonable?
If I go with the single NSTableView option, would I be better off if I input all the data into a single data source (say an NSDictionary) and then populating the table? The only problem that I see with this idea is what happens when a selection of the table is done.. How would I decipher which of the original location was selected.
Another idea/potential problem that just popped into my head ... if I take the data from the data source and populate the table directly, how would give the count of the table in the relevant NSTableView 'count' method.. Would adding the count of data store 1 and data store 2 do it?
Sorry if it's a bit jumbled up.. Thanks for any input!
You can definitely use multiple data sources for the data to be displayed in the table view, but they must all be funnelled through a single controller object that is assigned as the table view's datasource and which implements the NSTableViewDatasource protocol.
You will have to write some code in your controller object so that you keep track of the multiple source arrays that make up and supply the table view with the appropriate values for the number of items and the content of each item.
This is a very simplistic example:
- (NSInteger)numberOfRowsInTableView:(NSTableView *)aTableView
{
return [array1 count] + [array2 count];
}
- (id)tableView:(NSTableView *)aTableView objectValueForTableColumn:(NSTableColumn *)aTableColumn row:(NSInteger)rowIndex
{
if(rowIndex >= [array1 count])
{
return [array2 objectAtIndex:rowIndex - [array1 count]];
}
else
{
return [array1 objectAtIndex:rowIndex];
}
}
As for selection, well, your controller knows where it's getting its data from, so when the user selects a particular row it should be trivial to translate that row index to a matching object in one of your backing stores.
Depending on your application logic, it can make sense. The easiest way would be to set up a different source for every table section. Then, you could use the section number as a selector to your data base.
- (NSInteger) tableView: (UITableView *) tableView numberOfRowsInSection: (NSInteger) section
I'm pretty comfortable with obj-c, but I don't understand this method signature. Specifically why this method has all that extra stuff before the method name, and what it means. Like I get that the - is an instance method, and that the return type is NSInteger
but why is tableView: (UITableView *) tableView in front of the method name?
WHy do some instance methods for the UITableViewDataSource protocol have nothing infront of the name? numberOfSectionsInTableViewis defined differently.
Can someone explain it to me?
Lets break it down into parts:
-
This means it's an instance method. The alternative is + which means class method.
(NSInteger)
This is the return type of the method. In this case it's NSInteger.
tableView:
The first component of the selector name (which is, in full, tableView:numberOfRowsInSection:). The : indicates that a parameter follows.
(UITableView *)
The type of the parameter.
tableView
The name of the parameter. This is largely irrelevant in the method signature (except as a hint to the reader as to the purpose), but in the implementation this is the variable that is bound to that parameter.
numberOfRowsInSection:
The next component of the selector name.
(NSInteger)
The type of the second parameter.
section
The name of the second parameter.
Note, the only required space in this entire line is the one between tableView and numberOfRowsInSection:. All other spaces can be elided to produce
-(NSInteger)tableView:(UITableView*)tableView numberOfRowsInSection:(NSInteger)section
Though the most common format you'll find looks like this:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
Edit: Looks like there's still some confusion about the latter part of the question. The tableView: component of the selector is there to provide the UITableView* instance that's asking the question. All of the methods in the UITableViewDataSource protocol provide the sending tableview as an argument. Some of these methods have other arguments, and some don't. The ones that have additional arguments are all formatted as tableView:someOtherThing: (e.g. tableView:numberOfRowsInSection:), but this isn't required. It could be called numberOfRowsInTableView:forSection:, or numberOfRowsInSection:ofTableView:, or even foo:bar:, but it's a stylistic choice that was made by the API developer to preserve a consistent naming scheme that assist both the developer and the person reading the code later. As for the methods that don't take any other parameters, they look like numberOfSectionsInTableView: because that's just a natural name for the method. They can't be called tableView:numberOfSections because that's an illegal selector (all components after the first must have a parameter associated, and therefore must have a trailing :).
In each case a reference to the tableView that is asking for data or calling a delegate method is given to the user
// |
// V
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
// |
// V
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
That way if you have one datasource/delegate object that is in charge of multiple UITableView's you can distinguished between which one is asking for data/ is calling a method.
This is a pretty common pattern.
If you are using a UITableViewController the likelihood is that you will ignore the tableView parameter anyway as you are normally only dealing with the one UITableView
The reason for the ordering of the params e.g. tableView being at the beginning is probably preference and it reads better when there are multiple parameters, however when you only have the tableView paramater is must be the last.
I'm looking for a way to populate a table view from one single document, namely I want to load a .po file.
I would like each line of my table view to load one line of text from the PO file.
Ideally, I would like to have one line in the first column, and the corresponding translation in the second column (to get a clear view of the contents).
I have not worked much with table views yet so please forgive my ignorance!
I have done my research but I find the apple documentation confusing and very unclear -- and didn't find much online...
Thanks in advance for any help!
bbum is correct, you don't push data to your table, you provide it and the table displays it. Friday I did a quick mock-up on putting a text file displayed line by line, so maybe some of the code can help some.
Get a table view connected with an outlet to it's data source, then you can do something like this:
// Class variable in your table delegate object
NSArray* lineList;
IBOutlet NSTableView* table;
- (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView
{
return [lineList count];
}
- (id)tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row
{
return [lineList objectAtIndex:row];
}
// Be sure to use the proper encoding for your text file
// do something like this to load your text file.
- (void) loadData:(NSString*)ourPath
{
NSError* err = nil;
NSString* fullFileText = [NSString stringWithContentsOfFile:ourPath encoding:NSMacOSRomanStringEncoding error:&err];
if (err)
NSLog(#"Err: %#, %d", [err localizedDescription], [err code]);
if (fullFileText)
{
lineList = [[fullFileText componentsSeparatedByString:#"\n"] retain];
[table reloadData];
}
}
In your case you may want to hold an array of dictionaries, using a different key for both versions of your text. That way you can have two columns. The NSTableColumn will tell you which column you will be drawing into when tableView:objectValueForTableColumn: gets called. The other option you have here is making a custom cell that has two fields in it but that's probably overkill for what you're asking.
Note also that there are a number of other optional delegate calls you can add for more flexibility of how you show your data.
Additionally for more dynamic complex tasks I've found that bindings are better. They can be confusing if you're not comfortable with them though. For simple tables it's often just as easy to go this route. Good luck!
You don't push data to a table view, it pulls data from you. This can be done with either bindings or by implementing the table view data sour (which are a little bit different, but mostly the same, between the NS* and UI* platforms).
The NSTableView and UITableView documentation both have links to examples and programming guides. Read those and if you still don't get it, ask a specific question.
This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Method Syntax in Objective C
So I totally get the more common functions like:
-(void)viewDidUnload{
self.controllers = nil;
[super viewDidUnload];
}
However coming from a different programming background, I sometimes struggle with something like:
-(NSInteger) tableView: (UITableView *)tableView
numberOfRowsInSection:(NSInteger)section{
return [self.controllers count];
}
So I know the function returns a NSInteger. However I do get a little confused in how to mentally organize the rest of the function name ETC. I need to be able to visualize some structure. Like in this case is the function name numberOfRowsInSection with the parameter called section?
Help in this matter would be appreciated.
You can think of it like other programming languages by looking at
[object action:var withFoo:baz]
as
object."action:withFoo:"(var, baz)
Everything before colons is part of the method name, and everything after is arguments, so the name of the method is interleaved with the arguments passed to the method.
Yes, the way that Objective-C mixes arguments with parts of the method name seems weird at first. Everyone goes through a short adjustment period in this respect. But give it time -- after a little while, you may not want to ever see a comma-separated, parenthesized list of nameless parameters ever again.
In C++, you'd say something like:
Color *color = new Color(0.5, 0.7, 0.2, 0.8);
You know what those values mean, right? There's four of them, so obviously the parameters are in red, green, blue, alpha order. Or was it alpha, red, green, blue? Of course, it could also be hue, saturation, value, alpha... well, it doesn't really matter because you can always just look it up.
In Objective-C, you say:
UIColor *color = [[UIColor alloc] initWithRed:0.5 green:0.7 blue:0.2 alpha:0.8];
Isn't that better? You'll definitely still need to consult the documentation from time to time to remind yourself exactly what a method does, or what methods a class makes available. But you won't often find yourself consulting the docs just to figure out which parameter goes where.
Objective C has a descriptive way of writing methods..
-(NSInteger) tableView: (UITableView *)tableView numberOfRowsInSection:(NSInteger)section{}
It is a methods tableView, returning an NSInteger , takes two argument - a UITableView reference and an integer section. Now consider numberofRowsInSection as a description of what the argument is all about.Look at this example
-(NSInteger) calculateSum:(NSInteger)operand1 secondOperand:(NSInteger)operand2 andThirdOperand:(NSInteger)operand3{}
and I can call this methods as
[self calculateSum:var1 secondOperand:var2 andThirdOperand:var3];
Here "secondOperand" and "andThirdOperand" are not essential, I can write the above method as
-(NSInteger) calculateSum:(NSInteger)operand1 :(NSInteger)operand2 :(NSInteger)operand3{}
and call this method as
[self calculateSum:var1 :var2 :var3];
But first one is easy to read, if you tell what each variable is ..Hope this helps
Also see I used the word method instead of functions which is normally the objective c way..
(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
This is a method that accepts 2 arguments, a UITableView and an NSInteger. It's notated like this: -tableView:numberOfRowsInSection:.
Yep that's basically it. In obj-C the full method names include the arg names. I believe that convention originated from Smalltalk.