0
votes

I'll start with saying I'm reasonably new to IOS dev!

I have an array of data which looks like this -

    shopObjects *shop2 = [[shopObjects alloc] 
                initWithshopITitle:@"3 for 2 PT Sessions" 
                shopIGroup:@"standard" 
                shopIDesc:@"Special Offer - Get 3 bespoke PT sessions for the price of just one!" shopIPrice:@"00.20"  
                offer:false];

the shopIgroup field displays the section name.

I have listed the data into a tableview via the following -

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// NOT SURE HOW TO CALCULATE THIS!
return 3;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{

 // NOT SURE HOW TO CALCULATE THIS!
return 0;
}

- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
{
return 10; 
}


-(UITableViewCell *)tableView:(UITableView *)tableView
    cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
   static NSString *CellIdentifier =@"shopItems";
   shopObjects *s = [self.shopArray objectAtIndex:indexPath.row];
   UITableViewCell *cell = [tableView
                         dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
    cell.selectionStyle = UITableViewCellSelectionStyleNone;
    cell.textLabel.text=s.shopITitle;
    cell.textLabel.backgroundColor=[UIColor clearColor];
 return cell;
}

My questions are -

  1. How can I calculate the number of headers and the number of rows in each section required for the return statements in the above methods?
  2. How do I then apply my cell to the relevant section?

UPDATE My ShopObjects.m file for reference -

@implementation shopObjects

-(id)initWithshopITitle:(NSString *)shopITitleD shopIGroup:(NSString *)shopIGroupD   shopIDesc:(NSString *)shopIDescD shopIPrice:(NSString *)shopIPriceD offer:(Boolean )offerD{
 self= [super init];
  if(self){
    self.shopITitle = shopITitleD;
    self.shopIGroup = shopIGroupD;
    self.shopIDesc = shopIDescD;
    self.shopIPrice = shopIPriceD;
    self.offer = (offerD);



  }
   return self;


 }

ShopObjects.h file

import

@interface shopObjects : NSObject



@property(strong) NSString *shopITitle;
@property(strong) NSString *shopIGroup;
@property(strong) NSString *shopIDesc;
@property(strong) NSString *shopIPrice;
@property Boolean offer;


-(id)initWithshopITitle:(NSString *)shopITitleD shopIGroup:(NSString *)shopIGroupD shopIDesc:(NSString *)shopIDescD shopIPrice:(NSString *)shopIPriceD offer:(BOOL )offerD;


@end

array setup

    shopObjects *shop1 = [[shopObjects alloc] initWithshopITitle:@"1 x PT Session"     shopIGroup:@"running" shopIDesc:@"1 x 1hour fitness session with Zoe - bespoke fitness session.\n\nZoe's sessions focus on your general health and fitness so she will look at a bespoke fitness schedule that encompasses exersize, healthy eating, sleep and general lifestyle - to help you meet your goals.\n\nBe good to yourslef and give it a go.." shopIPrice:@"10.00"  offer:false];



  shopObjects *shop2 = [[shopObjects alloc] initWithshopITitle:@"3 for 2 PT Sessions" shopIGroup:@"offers" shopIDesc:@"Special Offer - Get 3 bespoke PT sessions for the price of just one!" shopIPrice:@"00.20"  offer:false];



  shopObjects *shop3 = [[shopObjects alloc] initWithshopITitle:@"1 x Running Club" shopIGroup:@"running" shopIDesc:@"1 x running club session - roup event - max group of 10." shopIPrice:@"15.00"  offer:false];


 shopObjects *shop4 = [[shopObjects alloc] initWithshopITitle:@"1 x Weights session" shopIGroup:@"weights" shopIDesc:@"1 x body building sesson" shopIPrice:@"10.90"  offer:false];



  self.shopArray = [NSArray arrayWithObjects:shop1, shop2, shop3,shop4,  nil];
  self.sectionData = [self.shopArray valueForKeyPath:@"@distinctUnionOfObjects.shopIGroup"];

UPDATE

For Greg - I have implemented your code and suggestions and app still crashes, I now get -

NSLOG - 2013-12-05 10:16:18.595 blah[3321:70b] Value of hello = 0 2013-12-05 10:16:18.596 blah[3321:70b] Value of hello = 1 2013-12-05 10:16:18.596 blah[3321:70b] Value of hello = 2 2013-12-05 10:16:27.962 blah[3321:70b] SECTIONS: 3 2013-12-05 10:16:27.962 blah[3321:70b] -[NSCFConstantString shopIGroup]: unrecognized selector sent to instance 0x1c7c38 2013-12-05 10:16:27.965 blah[3321:70b] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFConstantString shopIGroup]: unrecognized selector sent to instance 0x1c7c38' *** First throw call stack: ( 0 CoreFoundation 0x02bde5e4 __exceptionPreprocess + 180 1 libobjc.A.dylib 0x029618b6 objc_exception_throw + 44 2 CoreFoundation 0x02c7b903 -[NSObject(NSObject) doesNotRecognizeSelector:] + 275 3 CoreFoundation 0x02bce90b ___forwarding_ + 1019 4 CoreFoundation 0x02bce4ee _CF_forwarding_prep_0 + 14 5 blah 0x000198fb -[shopTVcontroller tableView:numberOfRowsInSection:] + 187 6 UIKit 0x00a33dc0 -[UISectionRowData refreshWithSection:tableView:tableViewRowData:] + 2510 7 UIKit 0x00a39384 -[UITableViewRowData rectForFooterInSection:heightCanBeGuessed:] + 288 8 UIKit 0x00a39495 -[UITableViewRowData heightForTable] + 68 9 UIKit 0x008ae181 -[UITableView _updateContentSize] + 400 10 UIKit 0x008c9333 -[UITableView setContentInset:] + 329 11 UIKit 0x008efeba -[UIViewController _setNavigationControllerContentInsetAdjustment:] + 538 12 UIKit 0x0091a9bc -[UINavigationController _computeAndApplyScrollContentInsetDeltaForViewController:] + 399 13 UIKit 0x0091ab2e -[UINavigationController _layoutViewController:] + 64 14 UIKit 0x0091b02b -[UINavigationController _updateScrollViewFromViewController:toViewController:] + 235 15 UIKit 0x0090f8ff -[UINavigationController _startCustomTransition:] + 2087 16 UIKit 0x0091c0c7 -[UINavigationController _startDeferredTransitionIfNeeded:] + 688 17 UIKit 0x0091ccb9 -[UINavigationController viewWillLayoutSubviews] + 57 18 UIKit 0x00a56181 -[UILayoutContainerView layoutSubviews] + 213 19 UIKit 0x0084c267 -[UIView(CALayerDelegate) layoutSublayersOfLayer:] + 355 20 libobjc.A.dylib 0x0297381f -[NSObject performSelector:withObject:] + 70 21 QuartzCore 0x0221a2ea -[CALayer layoutSublayers] + 148 22 QuartzCore 0x0220e0d4 _ZN2CA5Layer16layout_if_neededEPNS_11TransactionE + 380 23 QuartzCore 0x0220df40 _ZN2CA5Layer28layout_and_display_if_neededEPNS_11TransactionE + 26 24 QuartzCore 0x02175ae6 _ZN2CA7Context18commit_transactionEPNS_11TransactionE + 294 25 QuartzCore 0x02176e71 _ZN2CA11Transaction6commitEv + 393 26 QuartzCore 0x02177544 _ZN2CA11Transaction17observer_callbackEP19__CFRunLoopObservermPv + 92 27 CoreFoundation 0x02ba64ce __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION + 30 28 CoreFoundation 0x02ba641f __CFRunLoopDoObservers + 399 29 CoreFoundation 0x02b84344 __CFRunLoopRun + 1076 30 CoreFoundation 0x02b83ac3 CFRunLoopRunSpecific + 467 31 CoreFoundation 0x02b838db CFRunLoopRunInMode + 123 32 GraphicsServices 0x03c349e2 GSEventRunModal + 192 33 GraphicsServices 0x03c34809 GSEventRun + 104 34 UIKit 0x007e1d3b UIApplicationMain + 1225

36  libdyld.dylib                       0x0314f70d start + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException
(lldb) 

Error screen - enter image description here

2

2 Answers

1
votes

You can get section by get distinct sections of your objects from array. The best way is to add new @property of NSArray type (you will need it later) for example sectionData and in viewDidLoad load it with distinct values:

self.sectionData = [self.shopArray valueForKeyPath:@"@distinctUnionOfObjects.shopIGroup"];

Next you can just display a number of distinct object which gives you number of sections

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
    return [self.sectionData count];
}

To get number of rows per section you have to filter the array for section name like that:

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    //Get your section name from distinct array
    NSString *s = self.sectionData[section]
    //Filter your main array
    NSPredicate *pred = [NSPredicate predicateWithFormat:@"shopIGroup like %@", s];
    NSArray *filteredArr = [self.shopArray filteredArrayUsingPredicate:pred];
    return [filteredArr count];
}

To display the data you have to do something similar as above in cellForRowAtIndexPathMethod:

-(UITableViewCell *)tableView:(UITableView *)tableView
    cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
   static NSString *CellIdentifier =@"shopItems";
   UITableViewCell *cell = [tableView
                         dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
    cell.selectionStyle = UITableViewCellSelectionStyleNone;

    //Get your section name from distinct array
    NSString *s = self.sectionData[indexPath.section]
    //Filter your main array
    NSPredicate *pred = [NSPredicate predicateWithFormat:@"shopIGroup like %@", s];
    NSArray *filteredArr = [self.shopArray filteredArrayUsingPredicate:pred];
   shopObjects *rightS = filteredArr[indexPath.row]
    cell.textLabel.text=rightS.shopITitle;
    cell.textLabel.backgroundColor=[UIColor clearColor];
 return cell;
}

I would recommended you to change data structure. In this kind of project I use array(mainArray) with another array embedded (sectionArray) where I keep object. So I know that for example my first array contain another array of object for first section. And I can yes section like that:

[mainArray count]

And rows per section like that:

 mainArray[section].count

And data for each row:

mainArray[section][row]

Hope you find it useful.

0
votes

You can use TLIndexPathDataModel from TLIndexPathTools instead of an array. It can organize your data into sections and provide a bunch of handy APIs for implementing your data source and delegate methods like [dataModel numberOfRowsInSection:] and [dataModel itemForRowAtIndexPath:].

In your case, you'd create your data model like this:

NAArray *items = ...;// array of shopObjects
TLIndexPathDataModel *dataModel = [[TLIndexPathDataModel alloc] initWithItems:items sectionNameKeyPath:@"shopIGroup" identifierKeyPath:nil];