Switching between custom uitableviews from inside an uiviewcontroller - objective-c

So I have a UIViewController class called SocialMainViewController. It has an instance of a TwitterViewController (which inherits from an UITableViewController) and an instance of a FacebookViewController (which also inherits from an UITableViewController).
#interface SocialMainViewController ()
#property (strong, nonatomic) TwitterViewController* twitterVC;
#property (strong, nonatomic) FacebookViewController* facebookVC;
...
#end
#implementation SocialMainViewController
#synthesize twitterVC = _twitterVC;
#synthesize facebookVC = _facebookVC;
..
- (void)viewDidLoad
{
[super viewDidLoad];
UIColor* color = [[UIColor alloc] initWithRed:0.2 green:0.2 blue:0.2 alpha:1.0];
[self.navigationController.navigationBar setTintColor:color];
// Do any additional setup after loading the view
self.facebookVC = [[FacebookViewController alloc] init];
self.facebookVC.view.frame = self.view.bounds;
[self.view addSubview:self.facebookVC.view];
}
So the Facebook view controller gets all the information from facebook and store it in an array. But the cellForRowAtIndexPath on that FacebookViewController class never gets called and hence only an empty table view is visible.
I'm actually trying to switch between the facebookviewcontroller and twitterviewcontroller tableviews. That is why I had the two inside the socialmainviewcontroller.

Related

Cocoa app doesn't show textview

I'm an iOS developer and I want to create a simple desktop app. I thought the switch would go perfect but it doesn't.
I've created a cocoa app ( from the xCode template ). Now I don't want to use user interface builders and stuff so I wrote my first controller like this:
#interface MainViewController ()
#property (nonatomic, strong) NSTextView *test;
#end
#implementation MainViewController
-(instancetype) init
{
self = [super init];
if(self)
{
NSLog(#"%s", __PRETTY_FUNCTION__);
_test = [[NSTextView alloc] init];
[_test setString:#"DKDDK"];
[self.view addSubview:_test];
[_test mas_makeConstraints:^(MASConstraintMaker *make) {
make.edges.equalTo(self.view);
}];
}
return self;
}
#interface MainViewController : NSViewController
#end
And I just use the NSWindow that is created by the template:
#interface AppDelegate ()
#property (weak) IBOutlet NSWindow *window;
#end
#implementation AppDelegate
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
// Insert code here to initialize your application
MainViewController * mainView = [[MainViewController alloc] init];
[self.window.contentView addSubview:mainView.view];
mainView.view.frame = ((NSView*)self.window.contentView).bounds;
}
When I run the application it gives me:
[NSViewController loadView] loaded the "(null)" nib but no view was set.
I don't know how to solve this. How can I create an app without nib, just like you do on iOS?
If you aren't loading the view from a NIB then there is little need for a view controller.
Discard the view controller and subclass NSView instead, and set that as the window's content view.
Note: you are making a rod for your own back by not using IB.

Accessing View from ViewController

I created a ViewController in StoryBoard and linked it with the GamePanelViewController class.
Furthermore I linked the view of the ViewController with a second class called GamePanel which extends of UIView.
How can I access to the view which is created automatically by StoryBoard to perform some methods I implemented to the GamePanel class which is linked to the view by identity inspector?
GamePanel.h:
#import <UIKit/UIKit.h>
#import "Plattform.h"
#interface GamePanel : UIView
#property (strong, nonatomic) NSMutableArray *plattforms;
- (void)initGamePanel;
- (void)drawPlattforms:(CGContextRef)gc;
#end
GamePanel.m:
#import "GamePanel.h"
#implementation GamePanel
#synthesize plattforms;
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
}
return self;
}
- (void)initGamePanel{
self.backgroundColor = [UIColor redColor];
self.plattforms = [NSMutableArray new];
// Initialization code
for(int i = 0;i<8;i++){
for(int j = 0;j<6;j++){
[self.plattforms addObject:[[Plattform alloc] initWithXCord:(14+j*37) andYCoord:(58+14+i*37)]];
NSLog(#"Init");
}
}
}
If you have actually linked the viewController's view property with your custom view, then you can simply use self.view within you viewController to access it.
If you have just dragged a UIView onto your viewController in your storyboard (and not linked it to the viewController's view property), you will need to create an IBOutlet for it (control-drag from the view to your interface, and give it a name), then you can reference it with the name you give it e.g. self.myView.

OO approach to view controller classes in obj-c

I have 10 different pages built into a slider control in my app, these pages are setup using storyboards.
The only difference on each page is a different web view to display rich text and a different image as a background are used.
Is it possible for me to have one view controller for all 10 pages and setup some flags in the constructor which would be executed on every page when its loaded to tell it what image and web view to show? If so what would this look like?
Thanks,
Lewis.
You can create subclass of UIViewController, for example MyViewController.
And then replace your .h file with:
#import <UIKit/UIKit.h>
#interface MyViewController : UIViewController
#property (nonatomic, strong) UIWebView *myWebView;
#property (nonatomic, strong) UIImageView *myImageView;
- (id)initWithURLString:(NSString *)urlString image:(NSString *)imageName;
#end
And your .m file with:
#import "MyViewController.h"
#interface MyViewController ()
#end
#implementation MyViewController
#synthesize myWebView = _myWebView;
#synthesize myImageView = _myImageView;
- (id)initWithURLString:(NSString *)urlString image:(NSString *)imageName
{
self = [super init];
if (self) {
NSURL *url = [NSURL URLWithString:urlString];
NSURLRequest *urlRequest = [NSURLRequest requestWithURL:url];
_myWebView = [[UIWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 400)];
[_myWebView loadRequest:urlRequest];
_myImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:imageName]];
_myImageView.frame = CGRectMake(0, 400, 60, 60);
}
return self;
}
#end
And then just create an instances of your UIViewController subclass:
MyViewController *vCon = [[MyViewController alloc] initWithURLString:someURLString image:imageName];
I think the best approach would be to define a data source for your view controller. This data source would have the following interface, e.g.:
#protocol MyVCDataSource
- (NSUInteger)numberOfPages;
- (NSString*)htmlContentForPageIndex:(NSUInteger)index;
- (NSString*)backgroundForPageIndex:(NSUInteger)index;
#end
You would provide your view controller with a member called datasource that would be initialized in the initWithDatasource method:
#interface MyVC : UIViewController
...
#property (nonatomic, weak) id<MyVCDataSource> datasource;
- (id)initWithDatasource:(id<MyVCDataSource>)ds;
Then your view controller would just ask the data source for the HTML data or the background file name when it needs it:
- (void)viewDidLoad {
self.view.backgroundColor = GET_BACKGROUND_FROM_STRING([self.datasource backgroundForPageIndex:self.currentIndex]);
[self.webView loadHTMLString: [self.datasource htmlContentForPageIndex:self.currentIndex]];
....
}
I assumed that the protocol just returns strings, but indeed you can have it return what you need (e.g., an image, a color, an URL), it all depends on the internals of your class.
Finally, your datasource object could be any object (even your MyVC instance) and return its data by indexing into an array:
- (NSString*)htmlContentForPageIndex:(NSUInteger)index {
return [self.htmlPages objectAtIndex:index];
}
etc.

Can't get property from another class

I have a class RootViewController where I have a UIBarButtonItem declared. The method to display it is in another class FirstDetailViewController.
I am trying to access it in another class SecondDetailViewController, but it is always null. I tested with some other variables and they were null as well. Here's what I have:
RootViewController.h
#interface RootViewController : UITableViewController <UISplitViewControllerDelegate> {
}
#property (nonatomic, retain) UIBarButtonItem *rootPopoverButtonItem;
...
#end
RootViewController.m
#import "RootViewController.h"
#import "FirstDetailViewController.h"
#implementation RootViewController
#synthesize popoverController, splitViewController, rootPopoverButtonItem;
- (void)splitViewController:(UISplitViewController*)svc willHideViewController:(UIViewController *)aViewController withBarButtonItem:(UIBarButtonItem*)barButtonItem forPopoverController:(UIPopoverController*)pc {
NSLog(#"splitviewController will hide");
// Keep references to the popover controller and the popover button, and tell the detail view controller to show the button.
barButtonItem.title = #"Menu";
self.popoverController = pc;
self.rootPopoverButtonItem = barButtonItem;
UIViewController <SubstitutableDetailViewController> *detailViewController = [splitViewController.viewControllers objectAtIndex:1];
[detailViewController showRootPopoverButtonItem:rootPopoverButtonItem];
}
FirstDetailViewController.m
- (void)showRootPopoverButtonItem:(UIBarButtonItem *)barButtonItem {
NSLog(#"show root popover button item");
// Add the popover button to the toolbar.
NSMutableArray *itemsArray = [toolbar.items mutableCopy];
[itemsArray insertObject:barButtonItem atIndex:0];
[toolbar setItems:itemsArray animated:NO];
[itemsArray release];
}
SecondDetailViewController.h
#import "RootViewController.h"
#class RootViewController;
#interface SecondDetailViewController : UIViewController <SubstitutableDetailViewController, UIScrollViewDelegate, UITextFieldDelegate, UITextViewDelegate> {
...
}
#property (nonatomic, retain) RootViewController *root;
#end
SecondDetailViewController.m
#import "SecondDetailViewController.h"
#implementation SecondDetailViewController
#synthesize root;
...
NSLog(#"view class : %#", [root.splitViewController class]);
[detailViewController showRootPopoverButtonItem:root.rootPopoverButtonItem];
...
You probably aren't setting the "root" property of SecondDetailViewController to the instance of RootViewController that you want to access the UIBarButtonItem for. Then you're reading an uninitialized instance of RootViewController in your SecondDetailViewController code, and the only reason you don't get an error is that Objective C silently ignores calls to methods on nil objects (in this case the rootPopoverButtonItem getter method, which the root.rootPopoverButtonItem is shorthand for).
If your instance of "RootViewController" is called "myRootViewController", then somewhere in your code you have to do something like:
SecondDetailViewController *mySecondDetailViewController = [[SecondDetailViewController alloc] init];
mySecondDetailViewController.root = myRootViewController;
Then you'll be accessing the copy of RootViewController that has the bar button you want.

Objective C - iOS - UIWebView getting retained in ARC but Delegate methods are not being called

I am having an issue with ARC. It is not retaining the webview. The scenario is I have to send a webview from one viewcontroller to another one. The reason is when the user searches for something I want to take him to a new screen with some other options. (I have to use the same webview)
Here is the sample code: I have a ViewController1 which has a webview (I added it in the xib.) I am loading say google in it and once the user searches for something and when its done loading I have to take him to a new view controller and show the same webview in the new viewcontroller.
//ViewController1
#interface ViewController1 : UIViewController <UIWebViewDelegate>
#property (nonatomic, retain) UIWebView* testWebView;
#end
#implementation ViewController1
#synthesize testWebView;
- (void)viewDidLoad
{
[super viewDidLoad];
testWebView = [[UIWebView alloc]init];
testWebView.delegate = self;
[testWebView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:#"https://www.google.com"]]];
}
-(void)webViewDidFinishLoad:(UIWebView *)webView{
NSString *html = [testWebView stringByEvaluatingJavaScriptFromString:
#"document.body.innerHTML"];
if ([self.testWebView.request.url.absoluteString rangeOfString:#"output=search"].location != NSNotFound) {
ViewController2* newViewController = [[ViewController2 alloc] init];
[newViewController setTestWebView:self.testWebView];
[self.navigationController setViewControllers:[NSArray arrayWithObject:newViewController] animated:NO];
}
}
- (void)dealloc{
[self.testWebView stopLoading];
self.testWebView.delegate = nil;
self.testWebView = nil;
}
In the second view controller I am loading stackoverflow.com after a delay of 10 secs. The problem is it is loading stackoverflow fine, but it is not calling any of the delegate methods. Why?
#interface ViewController2 : UIViewController <UIWebViewDelegate>
#property (nonatomic, retain) UIWebView* testWebView;
#end
#implementation ViewController2
#synthesize testWebView;
- (void)viewDidLoad
{
[super viewDidLoad];
self.testWebView.delegate = self;
[self.view addSubview:testWebView];
[self performSelector:#selector(loadDifferentPage) withObject:nil afterDelay:10];
}
-(void)loadDifferentPage{
[self.testWebView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:#"http://www.stackoverflow.com/"]]];
}
-(void)webViewDidStartLoad:(UIWebView *)webView{
NSLog(#"%s", __PRETTY_FUNCTION__);
}
-(void)webViewDidFinishLoad:(UIWebView *)webView{
NSLog(#"%s", __PRETTY_FUNCTION__);
}
-(BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType{
NSLog(#"%s", __PRETTY_FUNCTION__);
return YES;
}
ViewController2 is retaining the webview but the delegate methods are not being called. Why?
Thanks
Sai
ViewController1 delloc method was causing the issue:
If I uncomment out self.textWebView.delegate = nil it works fine. The reason is first we are setting the webview for newViewController and later in dealloc of ViewController1 we are setting its delegate to nil.
- (void)dealloc{
[self.testWebView stopLoading];
if(self.testWebView.delegate == self)
self.testWebView.delegate = nil;
self.testWebView = nil;
}
First thing I noticed is you're not specifying the instance variable name when synthesizing a property. That's just asking for collisions. Here's an example of how that should look:
#interface ViewController1 : UIViewController <UIWebViewDelegate>
#property (nonatomic, strong) IBOutlet UIWebView* testWebView;
#end
#implementation ViewController1
#synthesize testWebView=_testWebView;
Also, I noticed in ViewController1 you used IBOutlet so everything is probably wired up in Interface Builder. Try making sure that you set the delegate property in Interface Bulider because you don't set it in the implementation. That would be why you're not receiving any messages.
ViewController2 looks like you set the delegate in code. The problem is, you DON'T have IBOutlet in front of the property. Normally this would mean that you simply setup the WebView in code, but in your example you do not ever create a new instance of a UIWebView control and assign it to self.testWebView. This means that if it does display on the page, it's because Interface Builder was used to create it. You couldn't set the delegate in code without using IBOutlet in front of the testWebView declaration so that's probably why it's not working in exmaple two.
#interface ViewController2 : UIViewController <UIWebViewDelegate>
#property (nonatomic, strong) UIWebView* testWebView; // Mising IBOutlet
#end
#implementation ViewController2
#synthesize testWebView;
- (void)viewDidLoad
{
[super viewDidLoad];
// missing any code that would create the webview [[UIWebView alloc] init]
self.testWebView.delegate = self; // You set the delegate in code here
[self.view addSubview:testWebView];
[self performSelector:#selector(loadDifferentPage) withObject:nil afterDelay:10];
}
Hope this helps, I'd have to see your full implementation to get more specific than this.