I have custom object and I have stored my values in Array. but I am bit stuck to show objects values form array. My code definition is here.
for (int i = 0; i < 20; i++)
{
Person *myPerson = [[Person alloc] init];
myPerson.name = #"Brian";
myPerson.age = [NSNumber numberWithInteger:23];
[myArray addObject:myPerson];
[myPerson release];
}
Now I want to show all 20 values which is stored in Array (name and age of person).
How will I show that values?
There are many different ways of showing the customers depending on what you want.
1. Print to the console
If you just want to print them out to the console, you can use:
for (int i = 0; i < 20; i++)
{
Person *thisPerson = [myArray objectAtIndex:i];
NSLog(#"%# has an age of %d", thisPerson.name, thisPerson.age);
}
additionally, you can use Fast Enumerators to neaten things up:
for (Person *thisPerson in myArray)
{
NSLog(#"%# has an age of %d", thisPerson.name, thisPerson.age);
}
2. Showing in a table view
You'll need a UITableView with an instance of UITableViewController that conforms to the UITableViewDataSource protocol.
This tutorial gives you an excellent walkthrough:
http://www.icodeblog.com/2008/08/08/iphone-programming-tutorial-populating-uitableview-with-an-nsarray/
If neither of these solutions suits, please provide more information about what you're trying to achieve.
Related
I have one NSMutableArray that has number of records (suppose 52).
for (int i=0;i<=52;i++) {
[arrSavedCalculation addObject:[NSString stringWithFormat:#"Bianca lb,Red %d",i]];
}
I want to give a paging Prev and Next button at bottom of tableview. and each page display 6 record.How can i do this. i also see this document but not success
http://www.ke-cai.net/2011/04/pagination-with-uitableview-in-ios.html
Try with these. Tested and found working. Can be improved.
#interface ViewController (){
//pageNumber will hold the current page index
NSInteger _pageNumber;
//keeping the max page number for ease of calculation
NSUInteger _maxPageNumber;
//the batch size
NSUInteger _numberOfVisibleRows;
}
#end
#implementation ViewController
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
//Main data array is formed
NSUInteger rows = 0;
NSMutableArray *tempArray = [NSMutableArray array];
while (rows<52) {
[tempArray addObject:[NSString stringWithFormat:#"Item %d",rows+1]];
rows++;
}
self.mainArray = [NSArray arrayWithArray:tempArray];
_pageNumber = 0;
_numberOfVisibleRows = 5;
_maxPageNumber = [self.mainArray count]/_numberOfVisibleRows;
self.subArray = [self subArrayForPageNumber:_pageNumber];
}
- (NSArray *)subArrayForPageNumber:(NSUInteger)pageNumber{
NSRange range = NSMakeRange(_pageNumber*_numberOfVisibleRows, _numberOfVisibleRows);
if (range.location+range.length>[self.mainArray count]) {
range.length = [self.mainArray count]-range.location;
}
return [self.mainArray subarrayWithRange:range];
}
- (IBAction)buttonPressed:(UIBarButtonItem *)button{
//Same method is used for calculating the page numbers
if (button.tag ==1) {
_pageNumber= MIN(_maxPageNumber, _pageNumber+1);
}else{
_pageNumber = MAX(0, _pageNumber-1);
}
self.subArray = [self subArrayForPageNumber:_pageNumber];
[self.tableView reloadData];
}
Source Code
you should take two array.
1) Your MAIN ARRAY containing all of objects.
2) A Temporary array contain only 6 objects.
While loading tableview use that Temporary Array.
keep a page counter which will count your current page.
According to your 52 objects you can have 52/6 = 9 page but last page contain only 4 object.
like.
#define kNumberOfObjectInOnePage 6
set self.page=0 in "viewDidLoad" //self.page is the page counter.
-(void)nextPage:(id)sender{
self.page++;
take 6 objects from main array into temp array
reload your table view.
}
-(void)previous:(id)sender{
self.page--;
take 6 previous object into temp array
reload your table view.
}
A simple solution is if you are accessing records from web service then ask to him provide the total number of records in initial hits as well as first 6 records to display. If you want to do paging you should keep page 0 or 1 at initial hit to service and as you got 6 records on first page and you find that total records which are given from service is more than the 6 then you have to show previous and next button otherwise no need of these button.
As you accessing the records you have to put into in an NSArray or in Coredata. When you press next buttonyou have to increase the page count and fetch next 6 records and save to DB or array and reload the table.
if you press previous button you have to remove last 6 object from array or you can delete or check some kind last 6 records to display and reload table.
Hope this helps.
I've 10 pan recognisers and want to assign to class property.
How can I increase numeric part of property name in for() loop?
for (int i=0; i < [_myArray count]; i++)
{
myClassInstance.recognizer = pangesture + i ?? // doesn't work of course. but how??
}
It's not fantastic form — definitely follow Caleb's comments wherever possible — but if you're really backed into a corner:
for(int i = 0; i < [_myArray count]; i++)
{
NSString *nameOfProperty = [NSString stringWithFormat:#"pangesture%d", i];
UIPanGestureRecognizer *recogniser = [self valueForKey:nameOfProperty];
}
That's using key-value coding; IBOutlets are necessarily KVC compliant or there'd be no way to load the NIB.
I've 10 pan recognisers and want to assign to class property. How can
I increase numeric part of property name in for() loop?
I'm not sure I understand your question fully, but assuming that you've got 10 gesture recognizers named g1 through g10 that you want to assign to 10 objects using a loop, a good approach would be to put those 10 gesture recognizers into an array and then make the assignment using the current index:
NSArray *recognizers = #[g1, g2, g3, g4, g5, g6, g7, g8, g9, g10];
if ([recognizers count < [_myArray count]) {
NSLog("Houston, we have a problem! Not enough gesture recognizers to go around.");
}
for (int i=0; i < [_myArray count]; i++)
{
myClassInstance.recognizer = recognizers[i]; // note the fancy "new" array access syntax!
}
If you're not allocating the gesture recognizers individually, then you can just create one each time though the loop:
for (MyClass *instance in _myArray) {
instance.recognizer = [[UIGestureRecognizer alloc] init...];
}
I'm having trouble making the sections in a UITableView. I've looked at the documentation for UILocalizedIndexedCollation as well as this sample code project:
https://developer.apple.com/library/ios/#samplecode/TableViewSuite/Listings/3_SimpleIndexedTableView_Classes_RootViewController_m.html#//apple_ref/doc/uid/DTS40007318-3_SimpleIndexedTableView_Classes_RootViewController_m-DontLinkElementID_18
What I have below is basically a straight copy/paste from the sample project. However, the sample project uses a custom object (TimeZoneWrapper.h) and then places the object in the correct section based on the object's instance variable (TimeZoneWrapper.localeName). However, I'm not using custom objects. I'm using just a bunch of regular NSStrings. So my question is what method on NSString should I pass to the #selector() to compare and place the string in the correct section array?
Currently, I'm calling NSString's copy method as a temporary hack to get things working (which it does), but I'm not sure if this is correct. A little explanation would be much appreciated!
- (void)configureSections {
// Get the current collation and keep a reference to it.
self.collation = [UILocalizedIndexedCollation currentCollation];
NSInteger index, sectionTitlesCount = [[collation sectionTitles] count]; // sectionTitles are A, B, C, etc.
NSMutableArray *newSectionsArray = [[NSMutableArray alloc] initWithCapacity:sectionTitlesCount];
// Set up the sections array: elements are mutable arrays that will contain the locations for that section.
for (index = 0; index < sectionTitlesCount; index++) {
NSMutableArray *array = [[NSMutableArray alloc] init];
[newSectionsArray addObject:array];
}
// Segregate the loctions into the appropriate arrays.
for (NSString *location in locationList) {
// Ask the collation which section number the location belongs in, based on its locale name.
NSInteger sectionNumber = [collation sectionForObject:location collationStringSelector:#selector(/* what do I put here? */)];
// Get the array for the section.
NSMutableArray *sectionLocations = [newSectionsArray objectAtIndex:sectionNumber];
// Add the location to the section.
[sectionLocations addObject:location];
}
// Now that all the data's in place, each section array needs to be sorted.
for (index = 0; index < sectionTitlesCount; index++) {
NSMutableArray *locationsArrayForSection = [newSectionsArray objectAtIndex:index];
// If the table view or its contents were editable, you would make a mutable copy here.
NSArray *sortedLocationsArrayForSection = [collation sortedArrayFromArray:locationsArrayForSection collationStringSelector:#selector(/* what do I put here */)];
// Replace the existing array with the sorted array.
[newSectionsArray replaceObjectAtIndex:index withObject:sortedLocationsArrayForSection];
}
self.sectionsArray = newSectionsArray;
}
Thanks in advance!
You should use #selector(self).
Using #selector(copy) will cause memory leaks in your project
My Requirement:
I have this straight forward requirement of listing names of people in alphabetical order in a Indexed table view with index titles being the starting letter of alphabets (additionally a search icon at the top and # to display misc values which start with a number and other special characters).
What I have done so far:
1. I am using core data for storage and "last_name" is modelled as a String property in the Contacts entity
2.I am using a NSFetchedResultsController to display the sorted indexed table view.
Issues accomplishing my requirement:
1. First up, I couldn't get the section index titles to be the first letter of alphabets. Dave's suggestion in the following post, helped me achieve the same: NSFetchedResultsController with sections created by first letter of a string
The only issue I encountered with Dave' suggestion is that I couldn't get the misc named grouped under "#" index.
What I have tried:
1. I tried adding a custom compare method to NSString (category) to check how the comparison and section is made but that custom method doesn't get called when specified in the NSSortDescriptor selector.
Here is some code:
#interface NSString (SortString)
-(NSComparisonResult) customCompare: (NSString*) aStirng;
#end
#implementation NSString (SortString)
-(NSComparisonResult) customCompare:(NSString *)aString
{
NSLog(#"Custom compare called to compare : %# and %#",self,aString);
return [self caseInsensitiveCompare:aString];
}
#end
Code to fetch data:
NSArray *sortDescriptors = [NSArray arrayWithObject:[[[NSSortDescriptor alloc] initWithKey:#"last_name"
ascending:YES selector:#selector(customCompare:)] autorelease]];
[fetchRequest setSortDescriptors:sortDescriptors];
fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest
managedObjectContext:managedObjectContext sectionNameKeyPath:#"lastNameInitial" cacheName:#"MyCache"];
Can you let me know what I am missing and how the requirement can be accomplished ?
This is a really inefficient first-pass at this problem, which I am going to rewrite eventually. But hopefully this will help you.
The idea of this is to "guarantee" getting a real table section index back when tapping a "standard" section index view. A standard section index view should have a magnifying lens icon for search, a hash mark (#) for non-alphabetical sections, and letters A through Z for alphabetical sections.
This standard view is presented regardless of how many real sections there are, or what they are made of.
Ultimately, this code maps section view indices to real-existing alphabetic section name paths in the fetched results controller, or to real-existing non-alphabetic (numerical) sections, or to the search field in the table header.
The user will only occasionally recreate the section index mapping array (_idxArray) on each touch of the section index, but recreating the array on each touch is obviously inefficient and could be tweaked to cache pre-calculated results.
There are a lot of places to start tightening this up: I could make the sectionIndexTitleLetters static string all uppercase from the start, for example. It's fast enough on a 3GS phone, though, so I haven't revisited this recently.
In the header:
static NSString *sectionIndexTitleLetters = #"abcdefghijklmnopqrstuvwxyz";
In the implementation of the table view data source:
- (NSArray *) sectionIndexTitlesForTableView:(UITableView *)tv {
if (tv != searchDisplayController.searchResultsTableView) {
NSMutableArray *_indexArray = [NSMutableArray arrayWithCapacity:([sectionIndexTitleLetters length]+2)];
[_indexArray addObject:#"{search}"];
[_indexArray addObject:#"#"];
for (unsigned int _charIdx = 0; _charIdx < [sectionIndexTitleLetters length]; _charIdx++) {
char _indexChar[2] = { toupper([sectionIndexTitleLetters characterAtIndex:_charIdx]), '\0'};
[_indexArray addObject:[NSString stringWithCString:_indexChar encoding:NSUTF8StringEncoding]];
}
return _indexArray;
}
return nil;
}
- (NSInteger) tableView:(UITableView *)tv sectionForSectionIndexTitle:(NSString *)title atIndex:(NSInteger)index {
if (tv != searchDisplayController.searchResultsTableView) {
if (index == 0) {
//
// This is the search bar "section"
//
[currentTableView scrollRectToVisible:[[currentTableView tableHeaderView] bounds] animated:YES];
return -1;
}
else if (index == 1) {
//
// This is the "#" section, which covers non-alphabetic section headers (e.g. digits 0-9)
//
return 0;
}
else {
//
// This is a bit more involved because the section index array may contain indices that do not exist in the
// fetched results controller's sections->name info.
//
// What we are doing here is building a "fake-index" array that will return a real section index regardless of
// whether the section index title being touched exists or not.
//
// The fake array will be of length of the section index title array, and each index will contain an unsigned
// integer from 1 to {numOfRealSections}.
//
// The value this array returns will be "nearest" to the real section that is in the fetched results controller.
//
NSUInteger _alphabeticIndex = index-2;
unsigned int _idxArray[26];
for (unsigned int _initIdx = 0; _initIdx < [sectionIndexTitleLetters length]; _initIdx++) {
_idxArray[_initIdx] = [[fetchedResultsController sections] count] - 1;
}
unsigned int _previousChunkIdx = 0;
NSNumberFormatter *_numberFormatter = [[NSNumberFormatter alloc] init];
NSLocale *_enUSLocale = [[NSLocale alloc] initWithLocaleIdentifier: #"en_US"];
[_numberFormatter setLocale:_enUSLocale];
[_enUSLocale release];
for (unsigned int _sectionIdx = 0; _sectionIdx < [[fetchedResultsController sections] count]; _sectionIdx++) {
NSString *_sectionTitle = [[[fetchedResultsController sections] objectAtIndex:_sectionIdx] name];
if (![_numberFormatter numberFromString:_sectionTitle]) {
// what's the index of the _sectionTitle across sectionIndexTitleLetters?
for (unsigned int _titleCharIdx = 0; _titleCharIdx < [sectionIndexTitleLetters length]; _titleCharIdx++) {
NSString *_titleCharStr = [[sectionIndexTitleLetters substringWithRange:NSMakeRange(_titleCharIdx, 1)] uppercaseString];
if ([_titleCharStr isEqualToString:_sectionTitle]) {
// put a chunk of _sectionIdx into _idxArray
unsigned int _currentChunkIdx;
for (_currentChunkIdx = _previousChunkIdx; _currentChunkIdx < _titleCharIdx; _currentChunkIdx++) {
_idxArray[_currentChunkIdx] = _sectionIdx - 1;
}
_previousChunkIdx = _currentChunkIdx;
break;
}
}
}
}
[_numberFormatter release];
return (NSInteger)_idxArray[_alphabeticIndex];
}
}
return 0;
}
I might be naive, but I don't understand why these solutions are so baroque. I did this:
In my model, I added a method:
-(NSString *)lastInitial {
return [self.lastname substringToIndex:1];
}
And in my tablecontroller I set the fetchedresultscontroller to use that method:
NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:self.managedObjectContext sectionNameKeyPath:#"lastInitial" cacheName:#"Master"];
Seems to work - is there a reason that this is a bad idea? Or am I benefitting from new features in ios5 or something?
I have a table view in which I'm using sectionIndexTitlesForTableView to display an index. However, when I scroll the table, the index scrolls with it. This also results in very slow refreshing of the table. Is there something obvious I could be doing wrong? I want the index to remain in place on the right while the table scrolls. This is the code I'm using for the index titles:
- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView {
NSMutableArray *tempArray = [[NSMutableArray alloc] init];
[tempArray addObject:#"A"];
[tempArray addObject:#"B"];
[tempArray addObject:#"C"];
[tempArray addObject:#"D"];
...
return tempArray;
}
You really should be creating the index list somewhere else (say, in your table controller's init or loadView methods) and retaining it as an instance variable for later use. Then in sectionIndexTitlesForTableView you only have to return that ivar. If it isn't a property with a retain attribute then make sure you retain it when created so it sticks around (and release it in dealloc).
An easy way to create it is:
self.alphabetIndex = [NSArray arrayWithArray:
[#"A|B|C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|T|U|V|W|X|Y|Z|#"
componentsSeparatedByString:#"|"]];
The actual letters would have to change depending on the language locale setting but this way it's a bit easier to localize.
You definitely don't want to be creating that temp array each time because it's going to get called a lot.
As far as the index scrolling away it may be related to your returning a new array each time. Try the above first and if it doesn't solve the problem then you may want to tweak the value for the table's sectionIndexMinimumDisplayRowCount property and see if it makes any difference.
I would avoid creating a new NSMutableArray and releasing it every time. Try creating those on viewDidLoad or the class constructor and just reference the pre-built array on sectionIndexTitesForTableView.
If you are not manipulating the array at all, you probably don't need the overhead of an NSMutableArray at all. Try switching it to a plain old NSArray by using the arrayWithObjects static autorelease constructor.
That should speed things up for you.
Make a static variable, it will be released on app exit.
static NSMutableArray* alphabet = nil;
+ (void)initialize {
if(self == [MyViewController class]){
NSUInteger const length = 'Z' - 'A' + 1;
alphabet = [[NSMutableArray alloc] initWithCapacity:length];
for(NSUInteger i=0; i<length; ++i){
unichar chr = 'A' + i;
[alphabet addObject:[NSString stringWithCharacters:&chr length:1]];
}
}
}