How open a viewController from inside a Static Library in Xcode? - ios

I have a static library that contains a view controller class.
How on a new project in Xcode after include the static library (and headers) can I call this viewController?
View controller on static library:
#import "VC.h"
#interface VC ()
#property (nonatomic, strong) UILabel *label;
#property (nonatomic, strong) UIWindow *window;
#end
#implementation VC
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
_window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
_window.backgroundColor = [UIColor whiteColor];
[self.view addSubview: _window];
[super viewDidLoad];
self.label = [[UILabel alloc] initWithFrame:CGRectMake(115.0f, 150.0f, 200.0f, 30.0f)];
self.label.text = #"hello world!";
[self.view addSubview:self.label];
// Do any additional setup after loading the view.
}
#end
I have tried to allocate this ViewController in a new project and call it... but do not work:
VC *vc = [[VC alloc] init];
[self presentViewController:vc animated:YES completion:nil];
Am I missing something else?
* UPDATE
After the last edit, now I can see the viewcontroller, but it's not on top of the main viewcontroller and it becomes black after it loads... any thoughts?

There are a few ways to do this. I would say the most simple way to do this is simply include your viewControllers .xib or storyBoard as files in a folder with the library. If there is no good reason why users cannot have access to this, it shouldn't be that big of an issue.
The other way to do it would be to use the universal framework to make your library. This will return two frameworks for you when you compile it, one with the suffix .framework and the other with the suffix .embeddedframework. The latter will have links to your resources.
The final way to do it is include it in your project as a bundle. This is a somewhat involved and non-intuive process compared to the above ones.
EDIT:
If you are doing it not with a storyboard or .xib file you need to actually alloc and init self.view. It isn't getting loaded in from a storyboard, so you need to load it yourself. That's the issue with this code.

I was missing the basic structure for the view controller.
Creating an UIWindow inside the viewController fixed the problem for me.
Full Source code:
Static library view controller file (VC.m):
#import "VC.h"
#interface VC ()
#property (nonatomic, strong) UILabel *label;
#property (nonatomic, strong) UIButton *button;
#property (nonatomic, strong) UIView *window;
#end
#implementation VC
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// CREATE UIVIEW INSIDE VIEW CONTROLLER
_window = [[UIView alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
_window.backgroundColor = [UIColor whiteColor];
// CREATE BUTTON TO CLOSE VIEW CONTROLLER AFTER IS SHOWN
_button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[_button addTarget:self action:#selector(closeWindow:) forControlEvents:UIControlEventTouchDown];
[_button setTitle:#"Close View" forState:UIControlStateNormal];
_button.frame = CGRectMake(115.0f, 150.0f, 200.0f, 30.0f);
// ADD BUTTON TO THE UIWINDOW
[_window addSubview: _button];
// ADD UIWINDOW TO VIEW CONTROLLER
[self.view addSubview: _window];
// Do any additional setup after loading the view.
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - Close ViewController
- (IBAction)closeWindow:(id)sender {
[self dismissViewControllerAnimated:YES completion:nil];
}
#end
After import the static library and headers to a new app you can invoke the view controller with an IBAction like this:
#import "VC.h" //header for viewcontroller code in static library
...
-(IBAction)callVC:(id)sender {
VC *vc = [[VC alloc] init];
[self presentViewController:vc animated:YES completion:nil];
}

Related

Performing method on another UIViewController

I am using following code to set the text of a UILabel in SViewController, From another ViewController FViewController
SViewController *vc = [self.storyboard instantiateViewControllerWithIdentifier:#"SViewController"];
[vc setTextForLabel:[NSNumber numberWithInt:1];];
[self.navigationController pushViewController:vc animated:YES];
The setTextForLabel method:
-(void) setTextForLabel: (NSNumber *)text {
textLabel = [[UILabel alloc] init];
[textLabel setText:[NSString stringWithFormat:#"%#",[text stringValue]]];
NSLog(#"The text is %#", textLabel.text);
}
I have declared the property for textLabel in .h file is as follows:
#property (nonatomic, retain) IBOutlet UILabel *textLabel;
And I have also set the IBOutlet in storyboard.
Now in console I see "The text is 1", but the UI is not showing anything!
What am I doing wrong?
remove this line
textLabel = [[UILabel alloc] init];
Also, you need to link the UILabel on interface to your #property (nonatomic, retain) IBOutlet UILabel *textLabel;
Or you may add this label manually to view
textLabel = [[UILabel alloc] init];
[textLabel setText:[NSString stringWithFormat:#"%#",[text stringValue]]];
[self.view addSubView:textLabel];
First of all go put
[vc setTextForLabel:[NSNumber numberWithInt:1]];
after you push the vc.
In your xib/storyboard if your label has something written in it, remove it, leave it blank.
If that doesn't work ... leave the setText method before the push one (as you wrote it initialy) and create a NSNumber member that will hold your value and apply it in viewDidAppear like so
-(void) setTextForLabel: (NSNumber *)text{
numberValue = text; // declared in .h as NSNumber *numberValue (only make it a property if you need acces to it from outside your class)
}
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated]; //this is important
[textLabel setText:[NSString stringWithFormat:#"%#",[numberValue stringValue]]];
}
Your problem is linked to the view lifecycle of SViewController. When you call [.. setTextForLabel] you don't know if the controller has loaded its views (And thus your UILabel have a good chance of not being created yet)
What you should do is use a NSString property on your controller, set it with the desire text and assigned it to the UILabel in the viewDidLoad of SViewController.
in SViewController.h
#propery (strong, nonatomic) NSString *textToDisplay;
in SViewController.m
-(void)viewDidLoad
{
[super viewDidLoad];
// Here you know all Outlet are loaded and connected
textLabel.text = textToDisplay
}
I did like this
#import "FViewController.h"
#import "SViewController.h"
#interface FViewController ()
#end
#implementation FViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
- (IBAction)do:(id)sender
{
SViewController *vc = [self.storyboard instantiateViewControllerWithIdentifier:#"SViewController"];
[self.navigationController pushViewController:vc animated:YES];
[vc setTextForLabel:[NSNumber numberWithInt:1]];
}
// in SViewController.h
#import <UIKit/UIKit.h>
#interface SViewController : UIViewController
#property (weak, nonatomic) IBOutlet UILabel *label;
-(void) setTextForLabel: (NSNumber *)text;
#end
// SViewController.m file
#import "SViewController.h"
#interface SViewController ()
#end
#implementation SViewController
#synthesize label;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
}
-(void) setTextForLabel: (NSNumber *)text{
// label.text = [text stringValue];
NSLog(#"%#",label);
[label setText:[text stringValue]];
}
#end
also check your label properties in storyboard are properly set

Classical MVC in Cocoa

I'm trying to structure some view-code out of the controller (obviously without using a nib). Therefore, I tried a simple example, but for some reason, I can't add the target to the button in the controller, rest is fine. Here's what I'm trying:
Controller.h:
#import <UIKit/UIKit.h>
#import "IndexView.h"
#interface IndexController : UIViewController
{
}
#property (nonatomic) IndexView *contentView;
#end
Controller.m
#import "IndexController.h"
#import "IndexView.h"
#interface IndexController ()
#end
#implementation IndexController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
self.contentView = [[IndexView alloc]init];
[self.view addSubview:self.contentView];
[self connectUIElements];
}
return self;
}
- (void) connectUIElements
{
[self.contentView.testButton addTarget:self action:#selector(testButtonClicked) forControlEvents:UIControlEventTouchUpInside];
}
#pragma mark --
#pragma mark UIHandler
- (void) testButtonClicked
{
NSLog(#"testbutton clicked");
}
#end
View.h
#import <UIKit/UIKit.h>
#interface IndexView : UIView
#property (nonatomic, strong) UIButton *testButton;
#end
View.m
#import "IndexView.h"
#implementation IndexView
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
[self setUpView];
}
return self;
}
- (id) init
{
self = [super init];
if (self) {
[self setUpView];
}
return self;
}
- (void) setUpView
{
[self setBackgroundColor:[UIColor whiteColor]];
self.testButton = [[UIButton alloc]initWithFrame:CGRectMake(10, 50, 100, 50)];
self.testButton.backgroundColor = [UIColor greenColor];
[self.testButton setTitle:#"hello, world" forState:UIControlStateNormal];
[self addSubview:self.testButton];
}
#end
I'm just exploring possibilities to get closer to a classical MVC pattern and a little farther away from Apples mediator-interpretation. Any idea what's wrong?
You have to create your view using initWithFrame:, which is the default initializer for UIView. (The reason that is does not work with a simple init - but I am guessing here! - might be that the views size is zero and therefore the touch events do not work.)

Use a nib as a table section header with nib class

I want to create a section header that loads a nib file and sets that as the header UIView. This nib file will also have an associated class where the outlets and actions are connected to so I want to load that class with the nib like normal.
I've scoured the web and found several similar answers but I can't get any to work for me. After playing around for a few days I managed to get the view to show correctly but it doesn't do anything despite adding connections and telling the text to show differently.
For example it should clear the section title text if it's init with nil and it does that yet it still shows the same text, attempts to change it doesn't reflect either and any connections made with the button aren't triggered.
Here is my view controller for the view
#interface ADUNewRowHeaderViewController : UIViewController
#property (strong, nonatomic) IBOutlet UILabel *sectionTitleField;
#property (strong, nonatomic) IBOutlet UIButton *addRowBtn;
#property(strong,nonatomic) NSString* sectionTitle;
- (id)initWithNibName:(NSString *)nibNameOrNil
bundle:(NSBundle *)nibBundleOrNil
title:(NSString*) titleOrNil;
#end
and here is the implementation
#implementation ADUNewRowHeaderViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil title:(NSString *)titleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self)
{
if(titleOrNil != nil)
{
[self setSectionTitle:titleOrNil];
}
else
{
[self setSectionTitle:#""];
}
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (void)setSectionTitle:(NSString *)sectionTitle
{
_sectionTitle = sectionTitle;
[[self sectionTitleField] setText:sectionTitle];
}
#end
in the actual table view controller it's listed as
#property(nonatomic, strong) ADUNewRowHeaderViewController* secHeader;
and in the implementation file under viewDidLoad as
[self setSecHeader:[[ADUNewRowHeaderViewController alloc] initWithNibName:nil bundle:nil title:nil]];
[[[self secHeader] addRowBtn] addTarget:self action:#selector(addNewRow:) forControlEvents:UIControlEventTouchUpInside];
and
-(UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
return [[self secHeader] view];
}
-(CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
{
return [[self secHeader] view].bounds.size.height;
}
this is the method declaration for the action
- (IBAction)addNewRow:(id)sender;
You should make a UIView, instead of a UIViewController, subclass. The .m would contain:
- (id)initWithFrame:(CGRect)frame
{
if (self = [super initWithFrame:frame])
{
[self setUp];
}
return self;
}
- (void)awakeFromNib
{
[super awakeFromNib];
[self setUp];
}
- (void)setUp
{
[[NSBundle mainBundle] loadNibNamed:#"YourNibName" owner:self options:nil];
CGRect frame = self.frame;
self.view.frame = CGRectMake(0, 0, frame.size.width, frame.size.height);
[self addSubview:self.view];
... do other initialisations here ...
}
And the .h:
#interface ADUNewRowHeaderView : UIView
#property (nonatomic, strong) IBOutlet UIView* view;
Then in the XIB: Make File's Owner of class ADUNewRowHeaderView, as usual. And connect the XIB's top-level View's Referencing Outlet to the view property above (i.e. in File's Owner).
You then have a UIView subclass you can place on another XIB (as a UIView which for which you set the Class to ADUNewRowHeaderView), or instantiate in code and add as subview.
(Alternatively you could create the UIView and it's subviews (buttons, labels, ...) in code; then you would not need a XIB. But this only works of course if the UIView is simple and has little own logic, and few UI elements that are easy to layout in code.)

Adding a Navigation Controller but navigation item not displaying

Originally I had a custom NavigationBar, without a navigation controller. I have a sliding menu.
On the home screen there is a tableview, with a list. I would like to be able to add items to this list. So, I had to add in a navigation controller after the fact. I added the navigation controller to the storyboard and linked it to my main view controller [the one with the list]. Then I dragged in a view controller. I dropped in a bar button item into the navigation item, and pushed it to the recently added view controller.
I ran my app and the app shows no navigation bar or navigation item whatsoever now. Originally I had a custom navigation bar.
I'm not too sure what's going on here. Thanks for any help.
- (void)customizeAppearance {
UIImage *NavBG = [UIImage imageNamed:#"nav bar.png"];
[[UINavigationBar appearance] setBackgroundImage:NavBG forBarMetrics:UIBarMetricsDefault];
init View Controller code from .m
#import "initViewController.h"
#import "ECSlidingViewController.h"
#import "MenuViewController.h"
#interface initViewController ()
#end
#implementation initViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
self.topViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"Main"];
}
from .h
#import "ECSlidingViewController.h"
#interface initViewController : ECSlidingViewController
#end
from main.m
#import "MainViewController.h"
#import "ECSlidingViewController.h"
#import "MenuViewController.h"
#interface MainViewController ()
#end
#implementation MainViewController
{
NSArray *toDoList;
NSIndexPath *selectedIndexPath;
}
#synthesize menuBtn;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
from main.h
#import <UIKit/UIKit.h>
#interface MainViewController : UIViewController <UITableViewDataSource, UITableViewDelegate>
{
}
#property (strong, nonatomic) UIButton *menuBtn; // go to MenuViewController.m and synthesize
#end
Second view controller.m file
#import "SecondViewController.h"
#import "ECSlidingViewController.h"
#import "MenuViewController.h"
#interface SecondViewController ()
#end
#implementation SecondViewController
#synthesize menuBtn;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Below is the same stuff pasted from MainViewController.m
// Do any additional setup after loading the view.
self.view.layer.shadowOpacity = 0.75f;
self.view.layer.shadowOpacity = 10.0f;
self.view.layer.shadowColor = [UIColor blackColor].CGColor;
if (![self.slidingViewController.underLeftViewController isKindOfClass:[MenuViewController class]]) {
self.slidingViewController.underLeftViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"Menu"];
}
[self.view addGestureRecognizer:self.slidingViewController.panGesture];
self.menuBtn = [UIButton buttonWithType:UIButtonTypeCustom];
menuBtn.frame = CGRectMake(8, 10, 34, 24);
[menuBtn setBackgroundImage:[UIImage imageNamed:#"menuButton.png"] forState:UIControlStateNormal];
[menuBtn addTarget:self action:#selector(revealMenu:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:self.menuBtn];
}
Here are all the arrays I use
From the image you are showing, it doesn't look like any of the VCs have the starting arrow to its left. If that is the case, go to SB, click on the Nav controller, go to Attributes inspector on the right,scroll down and check the "Is initial View Controller".
Hope this answers it.
Update: Guessing at your code, you are trying to modify an immutable NSArray. Change your declaration to NSMutableArray *toDoList.

iOS Custom Delegate Returns Nil after setDelegate called from viewController

I have been having a strange problem using a custom delegate class in ARC. In the viewcontroller after viewDidLoad I call the toolbars setDelegate method and assign the viewcontroller as the delegate.
Whenever I try to reference delegate, it is nil, even after being set in the
viewcontroller.
//MPToolbar.h
#import <UIKit/UIKit.h>
//Define the protocol for the delegate
#class MPToolBar;
#protocol MPToolBarDelegate <NSObject>
#required
- (void)writeButtonSelected;
- (void)writeButtonDeSelected;
#end
#interface MPToolBar : UIView{
id <MPToolBarDelegate> delegate;
}
#property(strong) UIButton *lastButton;
#property(strong) id <MPToolBarDelegate> delegate;
-(IBAction)buttonSelected:(id)sender;
-(void)resizeForOrientation:(UIInterfaceOrientation)orientation;
#end
//MPToolbar.m
#import "MPToolBar.h"
#implementation MPToolBar
#synthesize lastButton, delegate;
- (id)initWithFrame:(CGRect)frame
{
if ((self = [super initWithFrame:frame])) {
// Initialization code
}
NSArray *nibViews = [[NSBundle mainBundle] loadNibNamed:#"MPToolBar" owner:self options:nil];
[self addSubview:[nibViews objectAtIndex:0]];
return self;
}
#pragma button actions
-(IBAction)buttonSelected:(id)sender{
UIButton *btn = (UIButton *)sender;
if(lastButton && lastButton != btn)[self deselect:lastButton];
if (btn.selected){
[self deselect:btn];
return;
}
[btn setSelected:YES];
lastButton = btn;
switch (btn.tag) {
case 0:
[self.delegate writeButtonSelected];
break;
}
}
-(void)deselect:(UIButton *)btn{
[btn setSelected:NO];
switch (btn.tag) {
case 0:
[self.delegate writeButtonDeSelected];
break;
}
}
/*
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect
{
// Drawing code
}
*/
-(void)resizeForOrientation:(UIInterfaceOrientation)orientation{
if (UIInterfaceOrientationIsLandscape(orientation)) {
self.frame = CGRectMake(0, 44, 1024, 60);
}
if (UIInterfaceOrientationIsPortrait(orientation)) {
self.frame = CGRectMake(0, 44, 768, 60);
}
}
#end
//ViewTest.h
#import <UIKit/UIKit.h>
#import "MPToolBar.h"
#interface ViewTest : UIViewController <MPToolBarDelegate>
{
MPToolBar *toolBar;
}
#property(strong) MPToolBar *toolBar;
#end
//ViewTest.m
#import "ViewTest.h"
#interface ViewTest ()
#end
#implementation ViewTest
#synthesize toolBar;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
self.toolBar = [[MPToolBar alloc] initWithFrame:CGRectMake(0, 44, 1024, 60)];
[self.view addSubview:self.toolBar];
[self.toolBar setAlpha:1.0];
[self.toolBar setDelegate:self];
// Do any additional setup after loading the view from its nib.
}
#pragma mark - MPToolBar Delegate Methods
-(void)writeButtonSelected{
//set new annotation for write mode and size to screen bounds.
NSLog(#"writeButtonSelected");
}
- (void)writeButtonDeSelected{
NSLog(#"writeButtonDeSelected");
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return YES;
}
#end
Ok so I finally found the problem. In my xib file I had set the UIView class to my custom controls class name instead of setting files owner.
once I changed the first UIView in the xib back to a standard UIView and then set the files owner to my custom class all was right with the world again!
-Thanks for everyone who tried to help!
Several things that could be causing problems:
Do you actually declare your view controller as a MPToolBarDelegate in its header? (that code is not present).
These are the delegate functions in your code:
-(void)ButtonSelected;
-(void)ButtonDeSelected;
However, you're actually invoking this one:
[_delegate writeButtonSelected];
which is not part of your protocol.
Try changing your delegate declarations like this:
#interface MPToolBar : UIView{
id delegate;
}
#property (nonatomic, assign) id <MPToolBarDelegate> delegate;
then when you call your delegate method use this:
[self.delegate ButtonSelected];
Also, the original iPad is upgradeable to iOS 5.0. If you are using ARC you can't be compatible with 4.3 anyway, ARC only started at 5.0 as I understand it.
With a similar symptom for me, my problem was that the segue's destinationViewController was NOT the object I was expecting it to be, because it was embedded in a UINavigationController.
Easy fix. See here. Lose pointer to Delegate while going through Navigation Controller

Resources