I am trying to create a NSOutlineVew with a custom header group (parent node) for listed objects. (NOTE: I have cell-based NSOutlineView). For example it look like as the Xcode "Navigator" or Numbers sidebar. I used the default groups for the separation properties per category, but it's looks like not as what I want. I need a parent node (cell), which I'll can visually adjust (add a controls elements and image).
I tried to do this by passing an array of objects to NSDictionary, giving each group a certain specific key. And a result, via NSLog everything is displayed correctly, but the transfer of this variable as the source for the program NSOulineView fails.
ProjectViewController.h
#interface ProjectViewController : NSViewController <NSOutlineViewDataSource, NSObject> {
IBOutlet NSOutlineView *outlineView;
FSEntity *content;
}
#property (readonly, assign) NSMutableArray *objects;
#end
ProjectViewController.m
#implementation ProjectViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Initialization code here.
// Setting default path to the local file or directory
NSString *home = NSHomeDirectory();
NSURL *url = [[NSURL alloc] initFileURLWithPath:home];
content = [[FSEntity alloc] initWithURL:url];
[self defineContentNSOutlineView];
NSLog(#"Array: %#",_objects);
// Basic сonfiguration an instance NSOutlineView
[self configurationNSOutlineView];
} return self;
}
#synthesize objects = _objects;
- (id)outlineView:(NSOutlineView *)outlineView child:(NSInteger)index ofItem:(id)item {
return (item == nil) ? [content.children objectAtIndex:index] : [((FSEntity *)item).children objectAtIndex:index];
}
- (BOOL)outlineView:(NSOutlineView *)outlineView isItemExpandable:(id)item {
return (item == nil) ? content.children.count > 0 : ((FSEntity *)item).children.count > 0;
}
- (NSInteger)outlineView:(NSOutlineView *)outlineView numberOfChildrenOfItem:(id)item {
return (item == nil) ? content.children.count : ((FSEntity *)item).children.count;
}
- (id)outlineView:(NSOutlineView *)outlineView objectValueForTableColumn:(NSTableColumn *)tableColumn byItem:(id)item {
if ([item isKindOfClass:[FSEntity class]]) {
return [((FSEntity *)item) title];
}
return nil;
}
- (void)outlineView:(NSOutlineView *)outlineView willDisplayCell:(id)cell forTableColumn:(NSTableColumn *)tableColumn item:(id)item {
if ([cell isKindOfClass:[ImageAndTextCell class]]) {
ImageAndTextCell *textField = (ImageAndTextCell *)cell;
[textField setImage:[item icon]];
}
}
- (void)defineContentNSOutlineView {
NSMutableArray *objects = [NSMutableArray arrayWithObjects:[NSDictionary dictionaryWithObjectsAndKeys:#"FINDER", #"title", [NSArray arrayWithObjects:[NSDictionary dictionaryWithObject:content.children forKey:#"title"], nil], #"children",[NSNumber numberWithBool:YES], #"header", nil], nil];
_objects = objects;
}
- (void)configurationNSOutlineView {
[outlineView sizeLastColumnToFit];
[outlineView setFloatsGroupRows:NO];
[outlineView reloadData];
[outlineView expandItem:nil expandChildren:YES];
}
#end
To easier would imagine how it would look, I showed it on the scheme:
+--------------------------------------------+
| ▼ FINDER FILES ₪ ✱ |
| 03143553.file |
| ▶ Desktop |
| ▶ Documents |
| ▶ Downloads |
| ▶ Movies |
| ▶ Music |
| ▶ Pictures |
+--------------------------------------------+
and what I have now (NSOulineView without using NSTreeController);
+--------------------------------------------+
| 03143553.file |
| ▶ Desktop |
| ▶ Documents |
| ▶ Downloads |
| ▶ Movies |
| ▶ Music |
| ▶ Pictures |
+--------------------------------------------+
I know about the example Apple "SourceView", but I don't know how to add to the created group, array of objects (files and folders), NSTreeContoller display only the first elements of the hierarchy (without includes):
+--------------------------------------------+
| ▼ FINDER FILES |
| 03143553.file |
| Desktop |
| Documents |
| Downloads |
| Movies |
| Music |
| Pictures |
+--------------------------------------------+
Modified method of SourceView example:
- (void)addFinderSection {
[self addFolder:#"FINDER FILES"];
NSError *error = nil;
NSEnumerator *urls = [[[NSFileManager defaultManager] contentsOfDirectoryAtURL:self.url includingPropertiesForKeys:[NSArray arrayWithObjects: nil] options:(NSDirectoryEnumerationSkipsHiddenFiles) error:&error] objectEnumerator];
for (NSURL *url in urls) {
BOOL isDirectory;
if ([[NSFileManager defaultManager] fileExistsAtPath:[url path] isDirectory:&isDirectory]) {
if (isDirectory) {
[self addChild:[url path] withName:NO selectParent:YES];
} else {
[self addChild:[url path] withName:NO selectParent:YES];
}
}
}
[self selectParentFromSelection];
}
This method displays only the first objects, as shown it on the latter scheme.
And one more question, as I said before, how to add to the node ** "FINDER FILES" ** button to the right side of the cell.
Can you help me with this? I know, maybe is not so hard, but I just began learn Objective-C and I don't know how to do this. Thanks.
Based on the starting code you provided, I was able to get something working, using Cell-based NSOutlineViews. The code you posted seemed incomplete, so it was hard to know what exactly you wanted to get out of the missing FSEntity class. I just used foundation classes: NSArray for lists of nodes (i.e. root nodes and children), NSDictionaries for each node itself (both root nodes and sub-nodes), and NSURLs as the file-system reference. I tried to stay as close to your original code as possible. In the end, it looked something like this:
ProjectViewController.h
#interface ProjectViewController : NSViewController <NSOutlineViewDataSource, NSObject>
{
IBOutlet NSOutlineView *outlineView;
NSURL *content;
}
#end
ProjectViewController.m
#import "ProjectViewController.h"
#interface ProjectViewController () {
NSMutableArray* _objects;
}
#property (nonatomic, retain, readwrite) NSMutableArray* objects;
#end
#implementation ProjectViewController
#synthesize objects = _objects;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
if (self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]) {
// Initialization code here.
// Setting default path to the local file or directory
NSString *home = NSHomeDirectory();
content = [[NSURL alloc] initFileURLWithPath:home];
[self defineContentNSOutlineView];
NSLog(#"Array: %#",_objects);
// Basic сonfiguration an instance NSOutlineView
[self configurationNSOutlineView];
}
return self;
}
// nodes have 3 keys: title, url, icon
- (NSArray*)p_childrenForNode: (NSMutableDictionary*)node {
if (nil == node)
return self.objects;
NSArray* retVal = nil;
if (nil == (retVal = [node valueForKey: #"children"]))
{
NSMutableArray* children = [NSMutableArray array];
for (NSURL* urlInDir in [[NSFileManager defaultManager] contentsOfDirectoryAtURL: [node objectForKey: #"url"]
includingPropertiesForKeys: [NSArray arrayWithObjects: NSURLNameKey, NSURLEffectiveIconKey, nil]
options: 0
error: NULL])
{
id name = [urlInDir getResourceValue: &name forKey: NSURLNameKey error: NULL] ? name : #"<Couldn't get name>";
id icon = [urlInDir getResourceValue: &icon forKey: NSURLEffectiveIconKey error: NULL] ? icon : nil;
NSMutableDictionary* dict = [NSMutableDictionary dictionaryWithObjectsAndKeys: urlInDir, #"url", name, #"title", nil];
if (icon)
[dict setObject: icon forKey: #"icon"];
[children addObject: dict];
}
retVal = children;
if (children)
[node setValue: children forKey: #"children"];
}
return retVal;
}
- (id)outlineView:(NSOutlineView *)outlineView child:(NSInteger)index ofItem:(id)item {
NSMutableDictionary* itemDict = (NSMutableDictionary*)item;
NSArray* children = [self p_childrenForNode: itemDict];
return children.count > index ? [[[children objectAtIndex: index] retain] autorelease] : nil;
}
- (BOOL)outlineView:(NSOutlineView *)outlineView isItemExpandable:(id)item {
NSMutableDictionary* itemDict = (NSMutableDictionary*)item;
NSArray* children = [self p_childrenForNode: itemDict];
return children.count > 0;
}
- (NSInteger)outlineView:(NSOutlineView *)outlineView numberOfChildrenOfItem:(id)item {
NSMutableDictionary* itemDict = (NSMutableDictionary*)item;
NSArray* children = [self p_childrenForNode: itemDict];
NSInteger retVal = children.count;
return retVal;
}
- (id)outlineView:(NSOutlineView *)pOutlineView objectValueForTableColumn:(NSTableColumn *)tableColumn byItem:(id)item {
NSImage* icon = [item objectForKey: #"icon"];
NSString* title = [item objectForKey: #"title"];
id value = nil;
if (icon) {
[icon setSize: NSMakeSize(pOutlineView.rowHeight - 2, pOutlineView.rowHeight - 2)];
NSTextAttachment* attachment = [[[NSTextAttachment alloc] init] autorelease];
[(NSCell *)[attachment attachmentCell] setImage: icon];
NSMutableAttributedString *aString = [[[NSAttributedString attributedStringWithAttachment:attachment] mutableCopy] autorelease];
[[aString mutableString] appendFormat: #" %#", title];
value = aString;
} else {
value = title;
}
return value;
}
- (void)defineContentNSOutlineView {
// Make root object
NSMutableDictionary* rootObj = [NSMutableDictionary dictionaryWithObjectsAndKeys:
#"FINDER", #"title",
content, #"url",
nil];
id icon = [content getResourceValue: &icon forKey: NSURLEffectiveIconKey error: NULL] ? icon : nil;
if (icon)
[rootObj setObject: icon forKey: #"icon"];
// Set it
self.objects = [NSMutableArray arrayWithObject: rootObj];
}
- (void)configurationNSOutlineView {
[outlineView sizeLastColumnToFit];
[outlineView setFloatsGroupRows:NO];
[outlineView reloadData];
[outlineView expandItem:nil expandChildren:YES];
}
#end
I posted the whole, working sample project to GitHub.
Related
Xcode problem. I have a nsmutablearray that is pulling json objects. Example Company: Name, state, address, phone number, etc.
I am pulling the info just fine. And I want to display 1 of each state in a table view. It works fine but shows multibles of the same state. But I only want to show 1 of each state. I am using some code but it does not return any states. I have seen a lot of examples and this should work but it returns nothing. If I skip this code below it does show all states. i have also tried a for loop. And tried array to NSSet. Nothing is working. Any Ideas???
My problem is with this code...
//Create states only array...remove duplicate states here
NSArray *statesArray = [companies valueForKeyPath:#"#distinctUnionOfObjects.state"];
return statesArray;
Here is my whole code. Please help been struggling with this for a week.
#interface StatesTableViewController ()
#property (nonatomic) NSString *name;
#property (nonatomic) NSString *state;
#end
#implementation StatesTableViewController
NSArray *companies;
NSArray *statesArray;
- (void)viewDidLoad {
[super viewDidLoad];
NSString *address = #"http://www.companiesFeed";
NSURL *url = [[NSURL alloc] initWithString:address];
//laod the data on a background queue..
//if we were connecting to a an online url then we need it
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
companies = [self readCompanies:url];//, statesSet = [self readCompanies:url];
//now that we have the data, reload the table data on the main ui thread
[self.tableView performSelectorOnMainThread:#selector(reloadData) withObject:nil waitUntilDone:YES];
});
}
//new code
- (NSArray *)readCompanies:(NSURL *)url {
//create a nsurlrequest with the given Url
NSURLRequest *request = [NSURLRequest requestWithURL:url cachePolicy:
NSURLRequestReloadIgnoringLocalAndRemoteCacheData timeoutInterval:30.0];
//get the data
NSURLResponse *response;
NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:nil];
//now create a nsdictionary from the json data
NSDictionary *jsonDictionary = [NSJSONSerialization JSONObjectWithData:data
options:0 error:nil];
//create a new array to hold the comanies
NSMutableArray *companies = [[NSMutableArray alloc] init];
//get an array of dictionaries with the key "company"
NSArray *array = [jsonDictionary objectForKey:#"companies"];
//iterate throught the array of dictionaries
for (NSDictionary *dict in array) {
//create a new company object with information in the dictionary
Company *company = [[Company alloc] initWithJSONDictionary:dict];
//add the Company object to the array
[companies addObject:company ];
}
//Create states only array...remove duplicate states here
NSArray *statesArray = [companies valueForKeyPath:#"#distinctUnionOfObjects.state"];
return statesArray;
//return companies;
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark -table view controller methods
//change uniqueValue errors to companies
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger) section {
//return[companies count];
return [statesArray count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *cellID = #"CellIDState";
UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:cellID];
if (cell == nil){
//single line on table view
//cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:cellID];
// dual line on table view
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:cellID];
}
//edit single state
//Company *company = [companies objectAtIndex:indexPath.row];
Company *company = [statesArray objectAtIndex:indexPath.row];
//cell.textLabel.text = company.company_id;
cell.textLabel.text = company.state;
cell.detailTextLabel.text = [NSString stringWithFormat:#"%#",company.companyName];
//adds cheveron to tableviewl
[cell setAccessoryType: UITableViewCellAccessoryDisclosureIndicator];
return cell;
}
#pragma mark - navigation
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
}
#end
I was able to get the unique list of states by using a predicate and a block to check a set for existing states. Like so:
NSMutableArray *statesArray = [NSMutableArray array];
[companies filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(id evaluatedObject, NSDictionary *bindings) {
Company *dict = (Company *)evaluatedObject;
BOOL seen = [statesArray containsObject:dict];
if (!seen) {
[statesArray addObject:dict];
}
return !seen;
}]];
NSLog(#"unique states: %#", statesArray);
Where the companies array looks like this:
{[{
"company_id": "22",
"entityformSubmissionID": "22",
"companyName": "house of waffles",
"companySlogan": " where your home is!",
"address1": "123 here",
"address2": "thre",
"city": "everywhere",
"state": "CA",
"zipCode": "94531",
"phoneNumber": "777-777-7777",
"email": "test#test.com",
"additionalCompanyInfo": "all additional company info is going here",
"sales": "There are no sales!",
"rentalTerms": "Terms is dont break our stuff jerks!",
"companyLogo": "/16x16icon.png"
}]
I have a non doc-based app with table view with two columns, whose Value bindings are bound to two properties of the arrangedObjects of an array controller. I have a NSMutableArray in my AppDelegate that hold the data, as well as the corresponding #property and #synthesize. I implement key-value-coding accessor methods and use those when inserting data to the array in order to generate KVO notifications. I fill up my array with some NSDictionary objects from xml file. I've got all that working (modify, remove and add items), but what I'd like to do is write it back to xml file.
xmlData writeToFile:fileName atomically:YES
is writing to disk, but don't reflect changes when editing table view. There must be some tiny little thing I am forgetting. What is it?
Any suggestions would be very nice!
The code:
// AppDelegate.h
#import <Cocoa/Cocoa.h>
#interface AppDelegate : NSObject <NSApplicationDelegate>{
NSXMLDocument *xmlDoc;
NSXMLElement *root;
NSMutableArray *children;
}
#property (assign) IBOutlet NSWindow *window;
#property (nonatomic, copy)NSArray *children;
- (void)setChildren:(NSArray *)newChildren;
- (NSUInteger)countOfChildren;
- (id)objectInChildrenAtIndex:(NSUInteger)index;
- (void)insertObject:(id)object inChildrenAtIndex:(NSUInteger)index;
- (void)removeObjectFromChildrenAtIndex:(NSUInteger)index;
- (IBAction)addObject:(id)sender;
- (IBAction)saveXMLToFile:(id)sender;
- (void) populateTable;
#end
// AppDelegate.m
#import "AppDelegate.h"
#implementation AppDelegate
-(void) addObjectToChildren:(id)object{
[self insertObject:object inChildrenAtIndex:[self countOfChildren]];
}
#synthesize children;
- (id)init{
self = [super init];
if (self) {
children = [[NSMutableArray alloc] init];
}
return self;
}
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification{
[self populateTable];
}
#pragma mark - Indexed Accessors
- (void)setChildren:(NSArray *)newChildren{
if (children!=newChildren) {
children=[newChildren mutableCopy];
}
}
-(NSUInteger)countOfChildren{
return [self.children count];
}
-(id)objectInChildrenAtIndex:(NSUInteger)index{
return [self.children objectAtIndex:index];
}
- (void)insertObject:(id)object inChildrenAtIndex:(NSUInteger)index{
[children insertObject:object atIndex:index];
}
-(void)removeObjectFromChildrenAtIndex:(NSUInteger)index{
[children removeObjectAtIndex:index];
}
#pragma mark -
-(void)populateTable{
NSError *error=nil;
NSString *pathname = [#"~/myFile.xml" stringByExpandingTildeInPath];
NSURL *url = [NSURL fileURLWithPath:pathname];
xmlDoc = [[NSXMLDocument alloc] initWithContentsOfURL:url options:NSXMLDocumentTidyXML error:&error];
root = [xmlDoc rootElement];
NSArray *array=[root nodesForXPath:#"number" error:&error];
NSMutableArray *mArray=[[NSMutableArray alloc]init];
for (NSXMLElement *element in array) {
NSMutableDictionary *dict=[NSMutableDictionary dictionaryWithObjectsAndKeys:[element stringValue],#"id",#"number", #"name", nil];
[mArray addObject:dict];
}
[self setChildren:[NSArray arrayWithArray:mArray]];
}
#pragma mark - Actions
- (IBAction)addObject:(id)sender {
NSMutableDictionary *dict=[NSMutableDictionary dictionaryWithObjectsAndKeys:#"0",#"id",#"number", #"name", nil];
NSXMLElement *element=[[NSXMLElement alloc]initWithName:[dict objectForKey:#"name"] stringValue:[dict objectForKey:#"id"]];
[root insertChild:element atIndex:[self countOfChildren]];
[self addObjectToChildren:dict];
}
- (IBAction)saveXMLToFile:(id)sender {
NSString *fileName = [#"~/myFile.xml" stringByExpandingTildeInPath];
NSData *xmlData = [xmlDoc XMLDataWithOptions:NSXMLNodePrettyPrint];
if (![xmlData writeToFile:fileName atomically:YES]) {
NSBeep();
NSLog(#"Could not write document out...");
}
}
#end
The xml file:
<root>
<number>0</number>
<number>1</number>
<number>2</number>
<number>3</number>
<number>4</number>
<number>5</number>
</root>
When you change values in the tableview the underlying array is updated but not your XML document. You need to update your XML document or recreate it from the array to hold edited values.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
NSMutableArray Not showing actual values when NSLog in iphone application
I have NSMutableArray initialised as follows:
- (id)init
{
self = [super init];
if (self)
{
mySpotsArray = [[NSMutableArray alloc]init];
}
return self;
}
The array stores data of NSTable as follows:
//-----------------------------------------
- (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView {
return [mySpotsArray count];
[self saveMySpots];
}
//-----------------------------------------
- (id)tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row
{
Spot *sp = [mySpotsArray objectAtIndex:row];
NSString *identifier = [tableColumn identifier];
return [sp valueForKey:identifier];
[self saveMySpots];
}
//-----------------------------------------
- (void)tableView:(NSTableView *)tableView setObjectValue:(id)object forTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row
{
Spot *sp = [mySpotsArray objectAtIndex:row];
NSString *identifier = [tableColumn identifier];
[sp setValue:object forKey:identifier];
[self saveMySpots];
}
I am adding and deleting objects like this:
//-----------------------------------------
- (IBAction)addSpot:(id)sender
{
[mySpotsArray addObject:[[Spot alloc]init]];
[mySpotsTable reloadData];
[self saveMySpots];
}
//-----------------------------------------
- (IBAction)deleteSpot:(id)sender
{
NSInteger row = [mySpotsTable selectedRow];
[mySpotsTable abortEditing];
if (row !=-1)
{
[mySpotsArray removeObjectAtIndex: row];
}
[mySpotsTable reloadData];
[self saveMySpots];
}
I am saving and loading array content like this:
//-----------------------------------------
- (void) saveMySpots
{
savedSpots = [NSUserDefaults standardUserDefaults];
encodedMySpotsArrayObject = [NSKeyedArchiver archivedDataWithRootObject: mySpotsArray];
[savedSpots setObject: encodedMySpotsArrayObject forKey:[NSString stringWithFormat:#"MySpotsArrayKey"]];
}
//-----------------------------------------
- (void) loadMySpots
{
savedSpots = [NSUserDefaults standardUserDefaults];
decodedMySpotsArrayObject = [savedSpots objectForKey: [NSString stringWithFormat:#"MySpotsArrayKey"]];
mySpotsArray = [NSKeyedUnarchiver unarchiveObjectWithData: decodedMySpotsArrayObject];
}
Objects are encoded and decoded like this:
//-----------------------------------------
- (id)init
{
self = [super init];
if (self)
{
_mySpot = #"My Spot";
_localOffset = 0;
}
return self;
}
//-----------------------------------------
- (void)encodeWithCoder:(NSCoder *)encoder
{
[encoder encodeObject: self.mySpot forKey:#"MySpotKey"];
[encoder encodeInt: self.localOffset forKey:#"LocalOffsetKey"];
}
//-----------------------------------------
- (id)initWithCoder:(NSCoder *)decoder
{
self = [super init];
if( self != nil )
{
self.mySpot = [decoder decodeObjectForKey:#"MySpotKey"];
self.localOffset = [decoder decodeIntForKey:#"LocalOffsetKey"];
}
return self;
}
Everything is properly defined in their respective .h like this
NSMutableArray *mySpotsArray;
NSUserDefaults *savedSpots;
NSData *encodedMySpotsArrayObject;
NSData *decodedMySpotsArrayObject;
All works perfect on UI level, i.e. the table is properly displayed, added, deleted, saved and loaded. But when I am trying to NSLog like this:
NSLog(#"%#", mySpotsArray);
I get this:
2012-09-19 13:41:25.372 Spot[1541:303] (
"<Spot: 0x100674ab0>",
"<Spot: 0x100674c20>",
"<Spot: 0x100675040>"
)
I've also tried this:
NSString *strData = [[NSString alloc]initWithData: decodedMySpotsArrayObject encoding:NSUTF8StringEncoding];
NSLog(#"strData: %#", strData);
and I get this:
2012-09-19 13:41:25.371 Spot[1541:303] strData: (null)
I simply need to access NSMutableArray content and then convert it to strings. The actual content what I see on UI is a table with 2 columns and 3 rows:
Yerevan 2
London -1
Los Angeles -9
What am I doing wrong?
Thanks
I think this is the expected behavior.
How does the debugger know what it should print to the console? If you want it to print something else, e.g. some property on the Spot object, you need to provide Spot with a description method.
For example:
#import <Foundation/Foundation.h>
#interface Foo:NSObject {
NSString *_bar;
}
#property (nonatomic, copy) NSString *bar;
#end
#implementation Foo
#synthesize bar = _bar;
- (NSString *)description {
return self.bar;
}
#end
int main(int argc, char *argv[]) {
NSAutoreleasePool *p = [[NSAutoreleasePool alloc] init];
NSMutableArray *objs = [[NSMutableArray alloc] init];
Foo *myFoo = [Foo new];
myFoo.bar = #"Mine";
Foo *yourFoo = [Foo new];
yourFoo.bar = #"Yours";
[objs addObject:myFoo];
[objs addObject:yourFoo];
NSLog(#"Objs = %#",objs);
[p release];
}
prints this to the console:
2012-09-19 06:57:10.375 Untitled 2[59494:707] Objs = (
Mine,
Yours
)
But without the description method, this is what prints to the console:
2012-09-19 07:01:12.542 Untitled 2[59853:707] Objs = (
"<Foo: 0x7f9773c080c0>",
"<Foo: 0x7f9773c0a9b0>"
)
Add this method in your Spot class
- (NSString *)description
{
NSString *str = [[NSString alloc] initWithFormat:#"%# \n %# \n%#",Var1,Var2,var3];
return str;
}
replace Var1, Var2 and Var3 with your original variable name.
I have a search bar, i can search now, but when I enter a text to search, and click the cancel button. It does not give me back my first stage, meaning full of the items in the table.
For example: I search the item with word: a, it gives me all the a items, yes, it is right now, but when i hit the cancel button, i want the programme gives me all the items exist, not just a items.
Here is the code: please help me out. Thank you so much.
- (void)searchBarCancelButtonClicked:(UISearchBar *)aSearchBar
{
searchBar.text = #"";
[searchBar resignFirstResponder];
letUserSelectRow = YES;
searching = NO;
self.tableView.scrollEnabled = YES;
NSLog(#"what text after cancel now: %#", searchBar.text);
[self.tableView reloadData];
}
- (NSMutableArray *) searchTableView {
NSString *searchText = searchBar.text;
NSLog(#"search text: %#", searchText);
NSMutableArray *resultArray = [[NSMutableArray alloc] init];
NSMutableArray *tempArr = [[NSMutableArray alloc] init];
for (NSDictionary *dTemp in arrayData)
{
NSString *tempStr = [dTemp objectForKey:#"url"];
NSLog(#"sTemp string: %#",[ NSString stringWithFormat:#"%#", tempStr]);
NSRange titleResultsRange = [tempStr rangeOfString:searchText options:NSCaseInsensitiveSearch];
if (titleResultsRange.length > 0)
{
NSLog(#"1 count :%d", [resultArray count]);
[resultArray addObject:dTemp];
NSLog(#"2 count :%d", [resultArray count]);
[tempArr addObject:resultArray];
[resultArray release];
resultArray = [NSMutableArray new];
}
}
if (resultArray != nil) {
[resultArray release];
}
return tempArr;
}
- (void)searchBar:(UISearchBar *)aSearchBar textDidChange:(NSString *)searchText
{
NSLog(#"what text after cancel now: %#", searchBar.text);
if([searchText length] > 0) {
[sortedArray removeAllObjects];
searching = YES;
letUserSelectRow = YES;
self.tableView.scrollEnabled = YES;
NSMutableArray *searchArray = [self searchTableView];
sortedArray = [[NSMutableArray alloc] initWithArray:searchArray copyItems:YES];
for (int i = 0; i<[sortedArray count]; i++) {
NSLog(#"this is the search array: %#", [[sortedArray objectAtIndex:i] class]);
}
NSLog(#"sorted array: %d", [sortedArray count]);
}
else {
searching = NO;
letUserSelectRow = NO;
self.tableView.scrollEnabled = NO;
}
[self.tableView reloadData];
}
You don't need to override any of UISearchBar methods to accomplish this. The new way of doing this relies on the UISearchDisplay controller instead (specifically on shouldReloadTableForSearchString).
Declare your view controller to conform to UISearchDisplayDelegate protocol, and keep two instance variables: your model as NSArray (all data) and a filtered array as NSMutableArray (a subset of your data). The code you presently have in "searchTableView" would filter the content of the model and place it into the filtered NSMutableArray. Then you would override the following UITableView methods: -(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section and -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath. In each, before returning, make a comparison to determine whether your tableView argument is equal to self.searchDisplayController.searchResultsTableView. If it is, the user is looking at the filtered list and your should use the content of the filtered NSMutableArray to create the view, otherwise, the user is looking at the whole data set and you should use the content of the NSArray that holds your model. Take a look at the following Apple code for a simple example of what I described:
http://developer.apple.com/library/ios/#samplecode/TableSearch/Introduction/Intro.html
I have creating an address book application . My AddressController.h class is ---
#interface AddressController : NSObject {
IBOutlet id nameField;
IBOutlet id addressField;
IBOutlet id tableView;
NSMutableArray *records;
}
- (IBAction)addRecord:(id)sender;
- (IBAction)deleteRecord:(id)sender;
- (IBAction)insertRecord:(id)sender;
#end
Implementation class is as follow:-
#implementation AddressController
- (id)init
{
records = [[NSMutableArray alloc] init];
return self;
}
- (NSDictionary *)createRecord
{
NSMutableDictionary *record = [[NSMutableDictionary alloc] init];
[record setObject:[nameField stringValue] forKey:#"Name"];
[record setObject:[addressField stringValue] forKey:#"Address"];
[record autorelease];
return record;
}
- (IBAction)addRecord:(id)sender
{
[records addObject:[self createRecord]];
[tableView reloadData];
}
- (IBAction)deleteRecord:(id)sender
{
int status;
NSEnumerator *enumerator;
NSNumber *index;
NSMutableArray *tempArray;
id tempObject;
if ( [tableView numberOfSelectedRows] == 0 )
return;
NSBeep();
status = NSRunAlertPanel(#"Warning!", #"Are you sure that you want to delete the selected record(s)?", #"OK", #"Cancel", nil);
if ( status == NSAlertDefaultReturn )
{
enumerator = [tableView selectedRowEnumerator]; //enumerator here gets indexes of selected rows
tempArray = [NSMutableArray array];
while ( (index = [enumerator nextObject]) )
{
tempObject = [records objectAtIndex:[index intValue]]; // we store selected rows in temporary array
[tempArray addObject:tempObject];
}
[records removeObjectsInArray:tempArray]; // we delete records from 'records' array which are present in temporary array
[tableView reloadData];
}
}
- (IBAction)insertRecord:(id)sender
{
int index = [tableView selectedRow];
[records insertObject:[self createRecord] atIndex:index];
[tableView reloadData];
}
- (int)numberOfRowsInTableView:(NSTableView *)aTableView
{
return [records count];
}
- (id)tableView:(NSTableView *)aTableView objectValueForTableColumn:(NSTableColumn *)aTableColumn row:(int)rowIndex
{
id theRecord, theValue;
theRecord = [records objectAtIndex:rowIndex];
theValue = [theRecord objectForKey:[aTableColumn identifier]];
return theValue;
}
- (void)awakeFromNib
{
[tableView reloadData];
}
#end
I am able to add and delete records to/from address book. But when I start the application again all records are gone. I want to store records somewhere (like in user defaults ) so that when I start the application again existing records are shown in the address book.
I am not getting the idea how to do it using user defaults.
Please suggest solution.
Do not use user defaults for this. You may want to explore Core Data. Another option to explore is NSCoding.
NSCoding will have less of a learning curve, fairly simple to implement. Core Data is tougher to grasp, but would be the wiser choice in the long run.