Programatically create segue from xib file to viewcontroller in storyboard - ios

I use a library which has a xib file in objective-c
I have my storyboard that has swift classes
I need to create segue from that xib file to my storyboard and pass some data.
Tried this with no luck
XIB File
#import "IncomingMessageCell.h"
#implementation IncomingMessageCell
- (void)awakeFromNib {
UIImage * balloonImage = [UIImage imageNamed:#"bubble-left"];
balloonImage = [balloonImage resizableImageWithCapInsets:(UIEdgeInsets){36, 32, 18, 12}];
self.bubbleView.image = balloonImage;
self.avatarView.layer.cornerRadius = 25;
self.avatarView.clipsToBounds = YES;
self.avatarView.userInteractionEnabled = YES;
UITapGestureRecognizer *tapGesture1 = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(tapGesture:)];
tapGesture1.numberOfTapsRequired = 1;
[tapGesture1 setDelegate:self];
[self.avatarView addGestureRecognizer:tapGesture1];
}
- (void) tapGesture: (id)sender
{
UIViewController *vc = [[UIStoryboard storyboardWithName:#"MainStoryboard" bundle:nil] instantiateViewControllerWithIdentifier:#"yourVcIdentifier"];
[self.navigationController pushViewController:vc animated:YES];
}
- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
[super setSelected:selected animated:animated];
// Configure the view for the selected state
}
#end
How is that possible ?

Do like this in ViewController that holds tableview with this cell.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
IncomingMessageCell *cell = ...;
cell.avatarView.userInteractionEnabled = YES;
UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(handleTapGesture:)];
tapGesture.numberOfTapsRequired = 1;
[cell.avatarView addGestureRecognizer:tapGesture];
cell.avatarView.tag = 500 + indexPath.row; // To detect cell that image belongs to, because you use dequeue cell
return cell;
}
- (IBAction)handleTapGesture:(UITapGestureRecognizer *)tapGesture{
//Do you action
NSLog(#"Row tap : %ld",tapGesture.view.tag - 500);
UIViewController *vc = [[UIStoryboard storyboardWithName:#"MainStoryboard" bundle:nil] instantiateViewControllerWithIdentifier:#"yourVcIdentifier"];
[self.navigationController pushViewController:vc animated:YES];
}

Related

iOS - pass int between view controllers

I have an int pageNumber setup like so #property (nonatomic, assign) int pageNumber; which I am trying to pass between two view controllers.
It works the first time I tap a cell in the tableview, however if I tap a cell again the int does not get updated.
Any ideas? My code is below.
LeftMenuViewController.m
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[tableView deselectRowAtIndexPath:indexPath animated:YES];
UIStoryboard *mainStoryboard = [UIStoryboard storyboardWithName:#"MainStoryboard_iPhone"
bundle: nil];
UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:indexPath];
SoftwareCheckViewController *sc = [[SoftwareCheckViewController alloc] init];
if ([cell.textLabel.text isEqual: #"S:1 R:0"]) {
sc = [mainStoryboard instantiateViewControllerWithIdentifier: #"SoftwareCheckViewController"];
sc.pageNumber = 1;
}
else if ([cell.textLabel.text isEqual: #"S:1 R:1"]) {
sc = [mainStoryboard instantiateViewControllerWithIdentifier: #"SoftwareCheckViewController"];
sc.pageNumber = 2;
}
else if ([cell.textLabel.text isEqual: #"S:1 R:2"]) {
sc = [mainStoryboard instantiateViewControllerWithIdentifier: #"SoftwareCheckViewController"];
sc.pageNumber = 3;
}
[[NSNotificationCenter defaultCenter] postNotificationName:#"pageNumberNotification" object:self];
}
SoftwareCheckViewController.m
- (void)viewDidLoad
{
[super viewDidLoad];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(pageNumberMethod) name:#"pageNumberNotification" object:nil];
}
- (void)pageNumberMethod{
NSLog(#"pageNumber: %i", pageNumber);
}
You are creating new view controllers every time you tap a cell but you aren't doing anything with them. Setting sc.pageNumber is never going to have an effect if sc isn't the controller that's listening for a notification.
Also, even if you wanted a new controller, [[SoftwareCheckViewController alloc] init] is basically a waste because you then assign something different to sc right after.

UITableView memory bug

I have a problem with memory leak in UITableView. If I'm at the bottom of DetailViewController table and I want to go back to MasterViewController I have a crash. If I use UITableViewController, crash does not happen.
AppDelegate
_window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
_window.backgroundColor = [UIColor blackColor];
_window.rootViewController = [[UINavigationController alloc] initWithRootViewController:[[MasterViewController alloc] init]];
[_window makeKeyAndVisible];
MasterViewController
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
DetailViewController *detailViewController = [[DetailViewController alloc] init];
[self.navigationController pushViewController:detailViewController animated:YES];
}
DetailViewController
#interface DetailViewController ()
#property (nonatomic, strong) UITableView *tableView;
#end
#implementation DetailViewController
- (void)viewDidLoad {
[super viewDidLoad];
_tableView = [[UITableView alloc] initWithFrame:self.view.bounds];
_tableView.delegate = self;
_tableView.dataSource = self;
_tableView.rowHeight = 60;
[self.view addSubview:_tableView];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return 30;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if(cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
return cell;
}
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
NSLog(#"scrollViewDidScroll");
}
#end

UITableView bottom area keeps out of screen if navigationBar.translucent is NO;

I use UITableView instance as the subview of my ViewController's view, the table's content is higher than the screen so it is scrollable. Here is the code in AppDelegate:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)opts {
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
UINavigationController *nav = [[UINavigationController alloc] init];
self.window.rootViewController = nav;
[self.window makeKeyAndVisible];
UIViewController *controller = [[ViewController alloc] init];
[nav pushViewController:controller animated:YES];
// set to No cause the problem
nav.navigationBar.translucent = NO;
return YES;
}
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
_tableView = [[UITableView alloc] initWithFrame:self.view.frame style:UITableViewStylePlain];
_tableView.delegate = self;
_tableView.dataSource = self;
[self.view addSubview:_tableView];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return 20;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [[UITableViewCell alloc] init];
cell.textLabel.text = [NSString stringWithFormat:#"test %u", indexPath.row];
return cell;
}
#end
Now the problem is
if nav.navigationBar.translucent = YES, the content is scrolling right, the bottom line is visible if I scroll to bottom.
if nav.navigationBar.translucent = NO, the content isn't scrolling right, the bottom line automatically move out of the screen if I end the swip.
Seems like the auto hidden area is of the height of navigationBar, any one who knows how to fix it? I want it work the same no matter translucent = YES or translucent = NO.
Try this & let me know if it works:
self.tableView.contentInset = UIEdgeInsetsMake(44,0,0,0);
I figure out the solution, I set the tableView as the mainview of the controller, not a subview of the controller's mainview
[self setView:_tableView];
instead of
[self.view addSubview:_tableView];

ipad-how to open a popup view controller in a UITableViewCell

These are the files I am working on:
ChecklistViewController.h
ChecklistViewController.m
ChecklistTableViewCell.h
ChecklistTableViewCell.m
ChecklistTableViewCell.xib
DetailViewController.h
DetailViewController.m
DetailViewController.xib
I have a ChecklistViewController which displays a UITableView. Because I needed a different layout for the UITableViewCell, I have subclass UITableViewCell. I have created a nib file ChecklistTableViewCell.xib which has a UITableViewCell that contains a label, button and switch view. i have linked the UITableViewCell to a custom class ChecklistTableViewCell.
I have linked up the necessary outlets from the nib file to ChecklistTableViewCell class, and in ChecklistViewController cellForRowAtIndexPath I'm able to display label text.
In the UITableViewCell class file ChecklistTableViewCell, I have also linked and implemented a IBAction method that will be called when the button is clicked. When this method is called, how do I open DetailViewController as a popup?
Here is the snippet of my IBAction method:
-(IBAction)showPopup:(id)sender
{
NSLog(#"popup");
DetailViewController *vp = [[DetailViewController alloc] init];
vp.modalPresentationStyle = UIModalPresentationFormSheet;
vp.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
vp.view.superview.frame = CGRectMake(0, 0, 540, 620);
}
rdelmar is spot on with his comment. Because presentViewController:animated:completion is a method in the view controller, your ChecklistTableViewCell needs to make the view controller aware of the button click.
You have 2 choices:
Assuming your data source is your view controller, in your view controller:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
ChecklistTableViewCell *cell = ...;
cell.button.tag = indexPath.row; // or whatever appropriate
[cell.button addTarget:self action:#selector(buttonTapped:) forControlEvents:UIControlEventTouchUpInside];
return cell;
}
- (void)buttonTapped:(UIButton *)button
{
DetailViewController *vc = ...; // get your "popup" accordingly using button.tag
[self presentViewController:vc animated:YES completion:nil];
}
Or you can declare a protocol that your view controller adheres to:
// ChecklistTableViewCell.m
#protocol ChecklistTableViewCellDelegate
- (void)buttonTapped:(ChecklistTableViewCell *)sender;
#end
#implementation ChecklistTableViewCell : UITableViewCell
{
...
- (IBAction)showPopup:(id)sender // maybe change the name to something more appropriate
{
if ([self.delegate respondsToSelector:#selector(buttonTapped:)])
{
[self.delegate buttonTapped:self];
}
}
...
}
// ChecklistViewController.m
#implementation ChecklistViewController : ChecklistTableViewCellDelegate
{
...
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
ChecklistTableViewCell *cell = ...;
cell.tag = indexPath.row; // or whatever appropriate
cell.delegate = self;
...
return cell;
}
- (void)buttonTapped:(ChecklistTableViewCell *)sender
{
DetailViewController *vc = ...; // get your "popup" accordingly using sender.tag
[self presentViewController:vc animated:YES completion:nil];
}
...
}
If you want to show a detail view controller as pop up in iPad there is a control called UIPopoverController.
How to use UIPopoverController?
In .h file
UIPopoverController *popoverController;
In .m file
DetailviewController * objViewController = [[DetailviewController alloc]initWithNibName:#"DetailviewController" bundle:nil];
obj.delegate = (id )self; // if DetailViecontroller has any delegate.
popoverController = [[UIPopoverController alloc] initWithContentViewController:objViewController];
popoverController.popoverContentSize = CGSizeMake(320.0, 400.0);
UITableViewCell *cell = [tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:theRow inSection:1]];
CGRect rect=CGRectMake(cell.bounds.origin.x+600, cell.bounds.origin.y+10, 50, 30);
[popoverController presentPopoverFromRect:rect inView:self.view permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];

UITableViewController cells disappear if inside a UIScrollView

This is my storyboard:
My scrollView is contains 3 NavigationController(containing BubbleListController which is a sort of Table view). These 3 views are put one aside the other and this is the code:
ioBubbleListController.h
#import <UIKit/UIKit.h>
#interface ioBubbleListController : UITableViewController {
NSDictionary *bubbles;
}
#end
ioBubbleListController.m
#import "ioBubbleListController.h"
#interface ioBubbleListController ()
#property (nonatomic, retain) NSDictionary *bubbles;
#end
#implementation ioBubbleListController
#synthesize bubbles;
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) {
// Custom initialization
}
return self;
}
- (void)didReceiveMemoryWarning
{
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
#pragma mark - View lifecycle
- (void)viewDidLoad
{
[super viewDidLoad];
self.bubbles = [NSDictionary dictionaryWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"bubbles" ofType:#"plist"]];
// Uncomment the following line to preserve selection between presentations.
// self.clearsSelectionOnViewWillAppear = NO;
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
// self.navigationItem.rightBarButtonItem = self.editButtonItem;
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return [self.bubbles count];
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
return [[self.bubbles allKeys] objectAtIndex:section];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
NSString *continent = [self tableView:tableView titleForHeaderInSection:section];
return [[self.bubbles valueForKey:continent] count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"CountryCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
// Configure the cell...
NSString *continent = [self tableView:tableView titleForHeaderInSection:indexPath.section];
NSString *country = [[self.bubbles valueForKey:continent] objectAtIndex:indexPath.row];
cell.textLabel.text = country;
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
return cell;
}
#pragma mark - Table view delegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *continent = [self tableView:tableView titleForHeaderInSection:indexPath.section];
NSString *country = [[self.bubbles valueForKey:continent] objectAtIndex:indexPath.row];
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:nil
message:[NSString stringWithFormat:#"You selected %#!", country]
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alert show];
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
#end
This is my ioUIPager which puts one BubbleList aside the other
#import "ioUIPager.h"
#implementation ioUIPager
#synthesize scrollView;
- (void)viewDidLoad {
[super viewDidLoad];
[self scrollView].contentSize = CGSizeMake(self.scrollView.frame.size.width * 3, self.scrollView.frame.size.height);
UIStoryboard *sb = [UIStoryboard storyboardWithName:#"MainStoryboard_iPhone" bundle:nil];
// View1
UITableViewController *view1 = [sb instantiateViewControllerWithIdentifier:#"BubblesList"];
CGRect frame1;
frame1.origin.x = self.scrollView.frame.size.width * 0;
frame1.origin.y = 0;
frame1.size = self.scrollView.frame.size;
[self.scrollView addSubview:view1.view];
view1.view.frame = frame1;
view1.view.backgroundColor = [UIColor greenColor];
// View2
UIViewController *view2 = [sb instantiateViewControllerWithIdentifier:#"BubblesList"];
CGRect frame2;
frame2.origin.x = self.scrollView.frame.size.width * 1;
frame2.origin.y = 0;
frame2.size = self.scrollView.frame.size;
[self.scrollView addSubview:view2.view];
view2.view.frame = frame2;
view2.view.backgroundColor = [UIColor redColor];
// View2
UIViewController *view3 = [sb instantiateViewControllerWithIdentifier:#"BubblesList"];
CGRect frame3;
frame3.origin.x = self.scrollView.frame.size.width * 2;
frame3.origin.y = 0;
frame3.size = self.scrollView.frame.size;
[self.scrollView addSubview:view3.view];
view3.view.frame = frame3;
}
- (void)didReceiveMemoryWarning {
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
- (void)viewDidUnload {
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
self.scrollView = nil;
}
//- (void)dealloc {
// [scrollView release];
// [super dealloc];
//}
#end
Everything is rendered fine at first look, however any gesture/touch/tap I do on the UITableView/ioBubbleList, every cell disappears like this:
If from the storyboard I start from the navigator controller, then everything works fine. Any hint?
I solved this.
My issue was I was not keeping a reference of the UITableViewControllers and UITableViews I was adding inside the UIScrollView.
I just initialized and NSMutableArray and saved the UITableViewControllers the way I added the UITableViews into the UIScrollView.
EDIT
After some research I found that there is a smarter/better way to do this. Instead of keeping the instance inside our own array we should add the view controllers as childs to the container view controller (the UIViewController with the UIScrollView).
Here the explanation from apple docs:
https://developer.apple.com/library/ios/featuredarticles/ViewControllerPGforiPhoneOS/CreatingCustomContainerViewControllers/CreatingCustomContainerViewControllers.html
Here the code I used:
self.addChildViewController(tableViewController)
self.scrollView.addSubview(tableViewController.view)
tableViewController.didMoveToParentViewController(self)
Saving the tableViewControllers just in an array cannot keep track of the hierarchy inside the content view controller. This means that if we want to access the content view controller from the table view controllers we cannot. And several errors could happen with the UINavigationController if we are using it.

Resources