How to create top Navigation like Reddit App in Swift 3 - swift3

Here is the UI i want to create:
and what the complete UI looks like:
but i want to create first top Navigation. i tried https://github.com/subinspathilettu/SJSegmentedViewController
Which is working but it shows navigation after that it shows SegmentView.Could someone help me to create this UI it's same like reddit app screen after login.I need in swift.Thanks in advance

Okay. Here is the solution.
Step 1:
Take no. of buttons you want in a UIView.
Take UILabel for equal width of each button and height should be 1.0 and put it under each button.
Now give Outlets to each buttons and their respected labels in your ViewController.
Now take UIScrollView under this UIView and set constraints and give outlet.
Now you have to create ViewControllers for each Tab you want in Too Navigation.
For Example:-
I have a ProfileViewController.m like below.
#interface ProfileViewController ()<UIScrollViewDelegate>
#property (nonatomic,strong) AboutMeViewController *aboutMeVC;
#property (nonatomic,strong) AddressViewController *addressVC;
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
_btnAboutMe.selected = NO;
_btnAddress.selected = YES;
_btnPassword.selected = NO;
[self topButtonTapped:_btnAddress]; // This will call the navigation button tap method.
_controllerArray = [#[self.aboutMeVC,self.addressVC,[self.storyboard instantiateViewControllerWithIdentifier:#"changePasswordVC"]] mutableCopy];
[self addChildViewControllersOntoContainer:_controllerArray];
//self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:#"Left" style:UIBarButtonItemStylePlain target:self action:#selector(presentLeftMenuViewController:)];
[_leftBarButton setTarget:self];
[_leftBarButton setAction:#selector(presentLeftMenuViewController:)];
UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(profileTap:)];
tapGesture.numberOfTapsRequired = 1;
[_profilePicture addGestureRecognizer:tapGesture];
}
-(AboutMeViewController*)aboutMeVC
{
if (!_aboutMeVC) {
_aboutMeVC = [self.storyboard instantiateViewControllerWithIdentifier:#"aboutMeVC"];
}
_aboutMeVC.delegate = self;
return _aboutMeVC;
}
-(AddressViewController*)addressVC
{
if (!_addressVC) {
_addressVC = [self.storyboard instantiateViewControllerWithIdentifier:#"addressVC"];
}
return _addressVC;
}
// Adding all related controllers into the container
-(void) addChildViewControllersOntoContainer:(NSArray *)controllersArr
{
for (int i = 0; i < controllersArr.count; i++)
{
UIViewController *vc = (UIViewController *)[controllersArr objectAtIndex:i];
CGRect frame = CGRectMake(0, 0, self.containerScrollView.frame.size.width, self.containerScrollView.frame.size.height);
frame.origin.x = SCREEN_WIDTH * i;
vc.view.frame = frame;
[self addChildViewController:vc];
[self.containerScrollView addSubview:vc.view];
[vc didMoveToParentViewController:self];
}
self.containerScrollView.contentSize = CGSizeMake(SCREEN_WIDTH * controllersArr.count + 1, self.containerScrollView.frame.size.height - 99);
self.containerScrollView.pagingEnabled = YES;
self.containerScrollView.delegate = self;
}
// Scroll view delegate methods.
// This method will help you to change the navigation by sliding it.
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
NSInteger page = (scrollView.contentOffset.x / SCREEN_WIDTH);
[self changeButtonState:page];
//_selectedMenu = page;
//_segmentControl.selectedSegmentIndex = page;
NSLog(#"%#", NSStringFromCGSize(scrollView.contentSize));
// float xx = scrollView.contentOffset.x * (buttonWidth / SCREEN_WIDTH) - buttonWidth;
// [self.menuScrollView scrollRectToVisible:CGRectMake(xx, 0, SCREEN_WIDTH, self.menuScrollView.frame.size.height) animated:YES];
}
- (IBAction)topButtonTapped:(UIButton *)sender // Here is the method when you click on top button of your navigation bar.
{
[self changeButtonState:sender.tag];
[self.containerScrollView setContentOffset:CGPointMake(SCREEN_WIDTH * sender.tag, 0) animated:YES];
}
-(void)changeButtonState:(NSInteger)tag
{
if (tag == 0)
{
_btnAboutMe.selected = YES;
_btnAddress.selected = NO;
_btnPassword.selected = NO;
_btnAboutMe.fillColor = [GeneralClass getColorFromHex:kBlueColor withAlpho:1.0];
_btnAddress.fillColor = [GeneralClass getColorFromHex:kWhiteColor withAlpho:1.0];
_btnPassword.fillColor = [GeneralClass getColorFromHex:kWhiteColor withAlpho:1.0];
}
else if (tag == 1)
{
_btnAboutMe.selected = NO;
_btnAddress.selected = YES;
_btnPassword.selected = NO;
_btnAboutMe.fillColor = [GeneralClass getColorFromHex:kWhiteColor withAlpho:1.0];
_btnAddress.fillColor = [GeneralClass getColorFromHex:kBlueColor withAlpho:1.0];
_btnPassword.fillColor = [GeneralClass getColorFromHex:kWhiteColor withAlpho:1.0];
}
else if (tag == 2)
{
_btnAboutMe.selected = NO;
_btnAddress.selected = NO;
_btnPassword.selected = YES;
_btnAboutMe.fillColor = [GeneralClass getColorFromHex:kWhiteColor withAlpho:1.0];
_btnAddress.fillColor = [GeneralClass getColorFromHex:kWhiteColor withAlpho:1.0];
_btnPassword.fillColor = [GeneralClass getColorFromHex:kBlueColor withAlpho:1.0];
}
}
Your ViewController may look like this in your Storyboard.
I hope this will help you or at least give you some idea to develop what you need. Sorry for my answer in Objective C and some messy code. Actually I am in a hurry. But this will help you for sure. Thanks! :)
Note:- Please follow steps closely. You will find your solution for sure. Thanks. :)

Related

Tab bar image not working

I need your help here.
My app has 5 tab bars.
The first tab bar's image will be missing after make a phone call using openURL.
And this is only happen when running the app in iOS 8/9.
Below is the coding where I make a phone call:
-(void)callDistributor
{
NSString *phoneNo= [#"tel://" stringByAppendingString:phoneNumber_];
phoneNo = [phoneNo stringByReplacingOccurrencesOfString:#" " withString:#""];
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:phoneNo]];
}
Below is the coding (in delegate.m) where the tab bars are created:
- (void)addCustomTabbar {
NSArray *array =
[NSArray arrayWithObjects:#"products",
#"fav",
#"buy",
#"about",
#"settings", nil];
UIImage *buttonImage, *buttonImageSelected;
for (int i = 0; i < [array count]; i++) {
NSString *active =
[NSString stringWithFormat:#"%#_active.png", [array objectAtIndex:i]];
NSString *inActive =
[NSString stringWithFormat:#"%#.png", [array objectAtIndex:i]];
buttonImage = [UIImage imageNamed:inActive];
buttonImageSelected = [UIImage imageNamed:active];
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
button.tag = i;
button.autoresizingMask = (UIViewAutoresizingFlexibleRightMargin |
UIViewAutoresizingFlexibleLeftMargin |
UIViewAutoresizingFlexibleBottomMargin |
UIViewAutoresizingFlexibleTopMargin);
CGFloat heightDifference =
buttonImage.size.height -
tabBarController_.tabBar.frame.size.height;
button.frame = CGRectMake(i * buttonImage.size.width,
tabBarController_.view.frame.size.height -
tabBarController_.tabBar.frame.size.height - 1 - heightDifference,
buttonImage.size.width,
buttonImage.size.height);
[button setBackgroundImage:buttonImage forState:UIControlStateNormal];
[button setBackgroundImage:buttonImageSelected
forState:UIControlStateSelected];
[button addTarget:self
action:#selector(changeTabbar:)
forControlEvents:UIControlEventTouchDown];
[button setSelected:(i == 0)];
[tabBarController_.view addSubview:button];
}
addedTabBar_ = YES;
}
- (void)changeTabbar:(id)sender {
int tagNum = [sender tag];
tabBarController_.selectedIndex = tagNum;
for (UIView *view in tabBarController_.view.subviews) {
if ([view isKindOfClass:[UIButton class]]) {
UIButton *button = (UIButton *)view;
[button setSelected:(tagNum == button.tag)];
}
}
}
Only the first tab bar will missing after phone call, the other 4 tab bars are working fine.
Any ideas? Thanks in advance.

layer in menu singleton not displaying

I have made a singleton to handle menu changes (navigating through menu hierarchy) in my game. I don't know why the menu is not displaying. Please see my MenuManager classes singleton below.
MenuManager.h:
#interface MenuManager : NSObject
{
MenuLayerTypes currentMenuLayer;
CCLayer* runningLayer;
CCLayer* oldLayer;
}
+(MenuManager*)sharedMenuManager;
-(void)runMenuWithID:(MenuLayerTypes)menuLayerID;
#end
MenuManager.m:
#import "MenuManager.h"
#implementation MenuManager
static MenuManager* _sharedMenuManager = nil;
+(MenuManager*)sharedMenuManager
{
#synchronized([MenuManager class])
{
if (!_sharedMenuManager)
[[self alloc] init];
return _sharedMenuManager;
}
return nil;
}
+(id)alloc
{
#synchronized ([MenuManager class])
{
NSAssert(_sharedMenuManager == nil,
#"Attempted to allocated a second instance of the Menu Manager singleton");
_sharedMenuManager = [super alloc];
return _sharedMenuManager;
}
return nil;
}
-(id)init
{
self = [super init];
if (self != nil)
{
Layer = kMainMenuLayer; // default menu type
}
return self;
}
-(void)runMenuWithID:(MenuLayerTypes)menuLayerID {
//MenuLayerTypes oldMenuLayer = currentMenuLayer;
currentMenuLayer = menuLayerID;
oldLayer.tag = 321;
switch (menuLayerID)
{
case kMainMenuLayer:
CCLOG(#"main menu layer");
runningLayer = [MainMenuLayer node];
oldLayer = runningLayer;
break;
case kSettingsLayer:
runningLayer = [SettingsLayer node];
oldLayer = runningLayer;
break;
case kAckLayer:
runningLayer = [AckLayer node];
oldLayer = runningLayer;
break;
default:
CCLOG(#"Unknown ID");
return;
break;
}
MainMenuScene* mainMenuScene = (MainMenuScene *)[[CCDirector sharedDirector] runningScene];
// checks to see if a menu layer is already displayed before replacing it
if (![mainMenuScene getChildByTag:321]) {
[mainMenuScene addChild:runningLayer];
}
else {
[mainMenuScene removeChildByTag:321];
[mainMenuScene addChild:runningLayer];
}
}
#end
Also in the init of the MainMenuScene:
[[MenuManager sharedMenuManager] runMenuWithID:kMainMenuLayer];
How can I solve this display issue?

Cocos2d animation resume

I've added iAP in cocos2d following the ray tutorials (but changed a few things to fit cocos2d) but after I make a transaction the console log says 2013-08-19 16:32:12.626 Game[2483:907] Buying *product* ...
2013-08-19 16:32:13.208 Game[2483:907] cocos2d: animation stopped
2013-08-19 16:32:16.690 Game[2483:907] completeTransaction...
2013-08-19 16:32:16.725 Game[2483:907] User defaults for *product* are YES
So I know the transaction works, but the game never resumes it just freezes. Is there a way to resume the game after the transaction? [[CCDirector sharedDirector]resume] doesn't work so I think it may have to do with UIAlert View. Any help? Here is my iAPHelper.mm:
#import "IAPHelper.h"
#import <StoreKit/StoreKit.h>
NSString *const IAPHelperProductPurchasedNotification
#"IAPHelperProductPurchasedNotification";
#interface IAPHelper () <SKProductsRequestDelegate, SKPaymentTransactionObserver>
#end
#implementation IAPHelper {
SKProductsRequest * _productsRequest;
RequestProductsCompletionHandler _completionHandler;
NSSet * _productIdentifiers;
NSMutableSet * _purchasedProductIdentifiers;
}
- (id)initWithProductIdentifiers:(NSSet *)productIdentifiers {
if ((self = [super init])) {
// Store product identifiers
_productIdentifiers = productIdentifiers;
[[SKPaymentQueue defaultQueue] addTransactionObserver:self];
// Check for previously purchased products
_purchasedProductIdentifiers = [NSMutableSet set];
for (NSString * productIdentifier in _productIdentifiers) {
BOOL productPurchased = [[NSUserDefaults standardUserDefaults] boolForKey:productIdentifier];
if (productPurchased) {
[_purchasedProductIdentifiers addObject:productIdentifier];
NSLog(#"Previously purchased: %#", productIdentifier);
} else {
NSLog(#"Not purchased: %#", productIdentifier);
}
}
}
return self;
}
- (void)requestProductsWithCompletionHandler:(RequestProductsCompletionHandler)completionHandler {
_completionHandler = [completionHandler copy];
_productsRequest = [[SKProductsRequest alloc] initWithProductIdentifiers:_productIdentifiers];
_productsRequest.delegate = self;
[_productsRequest start];
}
#pragma mark - SKProductsRequestDelegate
- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response {
NSLog(#"Loaded list of products...");
_productsRequest = nil;
NSArray * skProducts = response.products;
for (SKProduct * skProduct in skProducts) {
NSLog(#"Found product: %# %# %0.2f",
skProduct.productIdentifier,
skProduct.localizedTitle,
skProduct.price.floatValue);
}
_completionHandler(YES, skProducts);
_completionHandler = nil;
}
- (void)request:(SKRequest *)request didFailWithError:(NSError *)error {
NSLog(#"Failed to load list of products.");
_productsRequest = nil;
_completionHandler(NO, nil);
_completionHandler = nil;
}
- (BOOL)productPurchased:(NSString *)productIdentifier {
return [_purchasedProductIdentifiers containsObject:productIdentifier];
}
- (void)buyProduct:(SKProduct *)product {
NSLog(#"Buying %#...", product.productIdentifier);
SKPayment * payment = [SKPayment paymentWithProduct:product];
[[SKPaymentQueue defaultQueue] addPayment:payment];
}
- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions
{
for (SKPaymentTransaction * transaction in transactions) {
switch (transaction.transactionState)
{
case SKPaymentTransactionStatePurchased:
[self completeTransaction:transaction];
break;
case SKPaymentTransactionStateFailed:
[self failedTransaction:transaction];
break;
case SKPaymentTransactionStateRestored:
[self restoreTransaction:transaction];
default:
break;
}
};
}
- (void)completeTransaction:(SKPaymentTransaction *)transaction {
NSLog(#"completeTransaction...");
[self provideContentForProductIdentifier:transaction.payment.productIdentifier];
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
}
- (void)restoreTransaction:(SKPaymentTransaction *)transaction {
NSLog(#"restoreTransaction...");
[self provideContentForProductIdentifier:transaction.originalTransaction.payment.productIdentifier];
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
}
- (void)failedTransaction:(SKPaymentTransaction *)transaction {
NSLog(#"failedTransaction...");
if (transaction.error.code != SKErrorPaymentCancelled)
{
NSLog(#"Transaction error: %#", transaction.error.localizedDescription);
}
[[SKPaymentQueue defaultQueue] finishTransaction: transaction];
}
- (void)provideContentForProductIdentifier:(NSString *)productIdentifier {
[_purchasedProductIdentifiers addObject:productIdentifier];
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:productIdentifier];
[[NSUserDefaults standardUserDefaults] synchronize];
[[NSNotificationCenter defaultCenter] postNotificationName:IAPHelperProductPurchasedNotification object:productIdentifier userInfo:nil];
NSLog(#"User defaults for %# are YES", productIdentifier);
}
- (void)restoreCompletedTransactions {
[[SKPaymentQueue defaultQueue] restoreCompletedTransactions];
}
#end
Before you popup your alert view try running...
[[CCDirector sharedDirector] stopAnimation];
When you get a response back from the user in the alertview callback or transaction completion run...
[[CCDirector sharedDirector] startAnimation];
Cocos doesn't often play well with UIKit/Cocoa callbacks so you need to pause rendering while they do their thing. We have similar behaviour for when the app goes into background/foreground in the app delegate...
-(void) applicationDidEnterBackground:(UIApplication*)application {
[[CCDirector sharedDirector] stopAnimation];
}
-(void) applicationWillEnterForeground:(UIApplication *)application {
[[CCDirector sharedDirector] startAnimation];
}
-(void)applicationDidBecomeActive:(UIApplication *)application {
[[CCDirector sharedDirector] resume];
}
Seems we use resume inside the applicationDidBecomeActive. Can't recall the full logic there but that has seemed to work for a bunch of our projects.

Aligning CCMenu at top the screen

I would have expected a 'Menu' button over a 'Switch Player' button at the upper left corner of the screen, but the upper part of the 'Menu' button is above the screen. Howcome? Is this a bug?
Left alignment is ok.
Thanks!
-(void) superSceneEnded
{
_sceneEnded = true;
CCMenu *menu = [CCMenu menuWithItems:nil];
menu.anchorPoint = ccp(0, 1); // Upper left corner
menu.position = ccp(2, _winSize.height - 2); // Almost at upp left corner of screen
[self addChild:menu];
[self addButton:menu :#"Menu" :#selector(goToMenu)];
if ([MatchMgr instance].currentMatch.isOnDevice)
{
[self addButton:menu :#"Switch player" :#selector(switchPlayer)];
}
[menu alignItemsVerticallyWithPadding:10];
}
-(void) addButton: (CCMenu*) menu: (NSString*) text: (SEL) selector
{
CCMenuItem *menuItem = [CCMenuItemImage itemFromNormalImage:#"button.png" selectedImage:#"button-pressed.png" target:self selector:selector];
menuItem.anchorPoint = ccp(0, 1); // Upper left corner
//menuItem.scale = 0.5;
[menu addChild:menuItem];
// The code below is not relevant for the question, but I keep it for your understanding.
CCLabelBMFont *bmText = [CCLabelBMFont labelWithString:text fntFile:#"MainFont.fnt"];
bmText.color = ccBLACK;
bmText.scale = 0.75;
bmText.alignment = NSTextAlignmentCenter;
bmText.position = ccp(75, 15);
[menuItem addChild: bmText];
}
It seems like this really is broken:
http://www.cocos2d-iphone.org/forum/topic/8261
I do my own placement of the buttons instead.
Here's my, not so fancy, code:
-(void) superSceneEnded
{
_sceneEnded = true;
CGFloat yPos = _winSize.height - 10;
CCMenu *menu = [CCMenu menuWithItems:nil];
menu.position = ccp(0, 0);
[self addChild:menu];
[self addButton:menu :#"Menu" :#selector(goToMenu): &yPos];
if ([MatchMgr instance].currentMatch.isOnDevice)
{
[self addButton:menu :#"Switch player" :#selector(switchPlayer): &yPos];
}
}
-(void) addButton: (CCMenu*) menu: (NSString*) text: (SEL) selector: (CGFloat*) yPos
{
CCMenuItem *menuItem = [CCMenuItemImage itemFromNormalImage:#"button.png" selectedImage:#"button-pressed.png" target:self selector:selector];
menuItem.scale = 0.5;
menuItem.position = ccp(42, *yPos);
*yPos -= 20;
[menu addChild:menuItem];
CCLabelBMFont *bmText = [CCLabelBMFont labelWithString:text fntFile:#"MainFont.fnt"];
bmText.color = ccBLACK;
bmText.scale = 0.75;
bmText.alignment = NSTextAlignmentCenter;
bmText.position = ccp(75, 15);
[menuItem addChild: bmText];
}

UITableView is not reloading

here is the situation:
I have a "UITableViewController" which loads objects with RestKits "RKFetchedResultsTableController". After clicking on a cell I switch to a detail UITableViewController also driven by a "RKFetchedResultsTableController" which gives me a corresponding answer text for the selected object.
The problem is now, if I go back to the first "UITableViewController" and select another object in the table the old answer text from the previous selected object is in the detail table. If I use the "pullToRefresh" function the table gets refreshed and the correct answer is loading.
Why is the old answer from the previous object still in the tableView and not the correct answer for the new selected Object even if I tell [tableController loadTable] in the viewWillAppear method.
AppDelegate:
#
interface AppDelegate ()
#property (nonatomic, strong, readwrite) RKObjectManager *objectManager;
#property (nonatomic, strong, readwrite) RKManagedObjectStore *objectStore;
#end;
#implementation AppDelegate
#synthesize window = _window, isAuthenticated;
#synthesize objectManager;
#synthesize objectStore;
- (void)initializeRestKit
{
//self.objectManager = [RKObjectManager managerWithBaseURLString:#"http://falling-ocean-1302.herokuapp.com"];
self.objectManager = [RKObjectManager managerWithBaseURLString:#"http://falling-ocean-1302.herokuapp.com"];
self.objectManager.serializationMIMEType = RKMIMETypeJSON;
self.objectManager.acceptMIMEType = RKMIMETypeJSON;
self.objectStore = [RKManagedObjectStore objectStoreWithStoreFilename:#"MMmtvzme.sqlite"];
self.objectManager.objectStore = self.objectStore;
self.objectManager.mappingProvider = [MMMappingProvider mappingProviderWithObjectStore:self.objectStore];
self.objectManager.client.cachePolicy = RKRequestCachePolicyNone;
RKLogConfigureByName("RestKit", RKLogLevelTrace);
RKLogConfigureByName("RestKit/Network", RKLogLevelTrace);
RKLogConfigureByName("RestKit/ObjectMapping", RKLogLevelTrace);
RKLogConfigureByName("RestKit/Network/Queue", RKLogLevelTrace);
// Enable automatic network activity indicator management
objectManager.client.requestQueue.showsNetworkActivityIndicatorWhenBusy = YES;
[objectManager.router routeClass:[MMRequest class] toResourcePath:#"/requests" forMethod:RKRequestMethodPOST];
[objectManager.router routeClass:[MMRequest class] toResourcePath:#"/requests" forMethod:RKRequestMethodDELETE];
[objectManager.router routeClass:[MMAnswer class] toResourcePath:#"/requests/:request_id/answers" forMethod:RKRequestMethodPOST];
}
Ok this is the code from the first UITableViewController
#interface MMMyRequestList ()
#property (nonatomic, strong) RKFetchedResultsTableController *tableController;
#end
#implementation MMMyRequestList
#synthesize tableController;
- (void)viewDidLoad
{
[super viewDidLoad];
[self configureRKTableController];
[self configureCellMapping];
[self useCustomNib];
}
- (void)configureRKTableController{
self.tableController = [[RKObjectManager sharedManager] fetchedResultsTableControllerForTableViewController:self];
self.tableController.autoRefreshFromNetwork = YES;
self.tableController.pullToRefreshEnabled = YES;
self.tableController.resourcePath = #"/requests";
self.tableController.variableHeightRows = YES;
NSSortDescriptor *descriptor = [NSSortDescriptor sortDescriptorWithKey:#"request_id" ascending:NO];
self.tableController.sortDescriptors = [NSArray arrayWithObject:descriptor];
tableController.canEditRows = YES;
}
- (void)configureCellMapping{
RKTableViewCellMapping *cellMapping = [RKTableViewCellMapping cellMapping];
cellMapping.cellClassName = #"MMRequestCell";
cellMapping.reuseIdentifier = #"MMRequest";
cellMapping.rowHeight = 100.0;
[cellMapping mapKeyPath:#"title" toAttribute:#"requestLabel.text"];
[cellMapping mapKeyPath:#"user.first_name" toAttribute:#"userLabel.text"];
cellMapping.onSelectCellForObjectAtIndexPath = ^(UITableViewCell *cell, id object, NSIndexPath* indexPath)
{
MMMyRequestListAnswer * uic = [self.storyboard instantiateViewControllerWithIdentifier:#"MMMyRequestListAnswer"];
MMRequest *request = [self.tableController objectForRowAtIndexPath:indexPath];
if ([uic respondsToSelector:#selector(setRequest:)]) {
[uic setRequest:request];
}
[self.navigationController pushViewController:uic animated:YES];
};
[tableController mapObjectsWithClass:[MMRequest class] toTableCellsWithMapping:cellMapping];
}
- (void)useCustomNib{
[self.tableView registerNib:[UINib nibWithNibName:#"MMRequestCell" bundle:nil] forCellReuseIdentifier:#"MMRequest"];
}
- (void)objectLoader:(RKObjectLoader*)objectLoader didFailWithError:(NSError*)error {
UIAlertView* alert = [[UIAlertView alloc] initWithTitle:#"Error"
message:[error localizedDescription]
delegate:nil
cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alert show];
NSLog(#"Hit error: %#", error);
}
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
/**
Load the table view!
*/
[tableController loadTable];
}
After clicking on a cell the Detail UIViewController come into action
interface MMMyRequestListAnswer ()
#property (nonatomic, strong) RKFetchedResultsTableController *tableController;
#end
#implementation MMMyRequestListAnswer
#synthesize tableHeaderView, requestTextLabel;
#synthesize request;
#synthesize tableController;
- (void)viewDidLoad
{
[super viewDidLoad];
[self configureRKTableController];
[self configureCellMapping];
[self useCustomNib];
}
- (void)configureRKTableController{
self.tableController = [[RKObjectManager sharedManager] fetchedResultsTableControllerForTableViewController:self];
self.tableController.autoRefreshFromNetwork = YES;
self.tableController.pullToRefreshEnabled = YES;
self.tableController.resourcePath = [NSString stringWithFormat:#"/requests/%i/answers", [self.request.request_id intValue]];
self.tableController.variableHeightRows = YES;
NSSortDescriptor *descriptor = [NSSortDescriptor sortDescriptorWithKey:#"answer_id" ascending:NO];
self.tableController.sortDescriptors = [NSArray arrayWithObject:descriptor];
}
- (void)configureCellMapping{
RKTableViewCellMapping *cellMapping = [RKTableViewCellMapping cellMapping];
cellMapping.cellClassName = #"MMRequestAnswerCell";
cellMapping.reuseIdentifier = #"MMAnswer";
cellMapping.rowHeight = 80.0;
[cellMapping mapKeyPath:#"text" toAttribute:#"answerLabel.text"];
[cellMapping mapKeyPath:#"user.first_name" toAttribute:#"userLabel.text"];
[tableController mapObjectsWithClass:[MMAnswer class] toTableCellsWithMapping:cellMapping];
}
- (void)useCustomNib{
[self.tableView registerNib:[UINib nibWithNibName:#"MMRequestAnswerCell" bundle:nil] forCellReuseIdentifier:#"MMAnswer"];
}
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
/**
Load the table view!
*/
[tableController loadTable];
}
The Object Mapping is handled in this Class:
#implementation MMMappingProvider
#synthesize objectStore;
+ (id)mappingProviderWithObjectStore:(RKManagedObjectStore *)objectStore {
return [[self alloc] initWithObjectStore:objectStore];
}
- (id)initWithObjectStore:(RKManagedObjectStore *)theObjectStore {
self = [super init];
if (self) {
self.objectStore = theObjectStore;
[self setObjectMapping:[self requestObjectMapping] forResourcePathPattern:#"/requests" withFetchRequestBlock:^NSFetchRequest *(NSString *resourcePath) {
NSFetchRequest *fetchRequest = [MMRequest fetchRequest];
return fetchRequest;
}];
[self setObjectMapping:[self answerObjectMapping] forResourcePathPattern:#"/requests/:request_id/answers" withFetchRequestBlock:^NSFetchRequest *(NSString *resourcePath) {
NSFetchRequest *fetchRequest = [MMAnswer fetchRequest];
fetchRequest.sortDescriptors = [NSArray arrayWithObject:[NSSortDescriptor sortDescriptorWithKey:#"answer_id" ascending:YES]];
return fetchRequest;
}];
[self setSerializationMapping:[self.requestObjectMapping inverseMapping] forClass:[MMRequest class]];
[self setSerializationMapping:[self.answerObjectMapping inverseMapping] forClass:[MMAnswer class]];
[self setSerializationMapping:[self.userObjectMapping inverseMapping] forClass:[MMUser class]];
}
return self;
}
- (RKManagedObjectMapping *)userObjectMapping {
RKManagedObjectMapping *mapping = [RKManagedObjectMapping mappingForEntityWithName:#"MMUser" inManagedObjectStore:self.objectStore];
mapping.primaryKeyAttribute = #"user_id";
[mapping mapAttributes:#"first_name", nil];
[mapping mapKeyPathsToAttributes:
#"id", #"user_id",
nil];
return mapping;
}
- (RKManagedObjectMapping *)answerObjectMapping {
RKManagedObjectMapping *mapping = [RKManagedObjectMapping mappingForEntityWithName:#"MMAnswer" inManagedObjectStore:self.objectStore];
mapping.primaryKeyAttribute = #"answer_id";
[mapping mapAttributes:#"text",#"request_id",#"user_id", nil];
[mapping mapKeyPathsToAttributes:
#"id", #"answer_id",
nil];
[mapping mapKeyPath:#"user" toRelationship:#"user" withMapping:[self userObjectMapping]];
[mapping mapKeyPath:#"request" toRelationship:#"request" withMapping:[self requestObjectMapping]];
return mapping;
}
- (RKManagedObjectMapping *)requestObjectMapping {
RKManagedObjectMapping *mapping = [RKManagedObjectMapping mappingForEntityWithName:#"MMRequest" inManagedObjectStore:self.objectStore];
mapping.primaryKeyAttribute = #"request_id";
[mapping mapAttributes:#"title",#"user_id", nil];
[mapping mapKeyPathsToAttributes:
#"id", #"request_id",
nil];
[mapping mapKeyPath:#"user" toRelationship:#"user" withMapping:[self userObjectMapping]];
return mapping;
}
OK Figured it out!!! Some digging revealed that I was loading my UITableviewcontroller BEFORE the mapping provider.
The fix was, to take [self initialiserestkit] method in - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
and put it before any of the code in this method (i.e. make [self initialiserestkit] the first line of the didfinishlaunchingwithoptions method.
Issue solved. Now the tableview is loaded AFTER the mappings so everything works as it should.