So here's my WSWordlistTableView.h:
#import <UIKit/UIKit.h>
#import <Foundation/Foundation.h>
#interface WSWordlistTableView : UITableView {
}
#property (nonatomic, assign) id <UITableViewDataSource> datasource;
#property (nonatomic, assign) id <UITableViewDelegate> delegate;
- (id)initWithFrame:(CGRect)frame;
#end
As you can see, there are delegate and datasource properties.
My WSWordlistTableViewController.h:
#import <UIKit/UIKit.h>
#import "WSWordlistManager.h"
#import "WSUserManager.h"
#interface WSWordlistTableViewController : UITableViewController <UITableViewDelegate, UITableViewDataSource>
#end
So, I'm building a sliding drawer view with this table that slides over the main VC. Here is the method in the main VC that creates the view and controller and then slides them onto screen:
- (IBAction)slideWordlistView:(id)sender {
if(!self.wordlistTableView ) {
CGRect frame = CGRectMake(30, 340, 100, 310);
self.wordlistTableView = [[WSWordlistTableView alloc] initWithFrame:frame];
}
[self.view bringSubviewToFront:self.wordlistTableView];
if(!self.wordlistTableViewController) {
self.wordlistTableViewController = [[WSWordlistTableViewController alloc] init];
}
self.wordlistTableViewController.view.frame = self.wordlistTableView.bounds;
self.wordlistTableViewController.view.autoresizingMask = self.wordlistTableView.autoresizingMask;
[self addChildViewController:self.wordlistTableViewController];
[self.wordlistTableView addSubview:self.wordlistTableViewController.view];
[self.wordlistTableViewController didMoveToParentViewController:self];
// *** THESE LINES THROW THE ERRORS
self.wordlistTableView.delegate = self.wordlistTableViewController;
self.wordlistTableView.datasource = self.wordlistTableViewController;
CGFloat newX = kVisibleX;
NSLog(#"newX = %f", newX);
[UIView animateWithDuration: .25
animations:
^{
CGRect drawerFrame = self.wordlistTableView.frame;
drawerFrame.origin.x = newX;
self.wordlistTableView.frame = drawerFrame;
}];
}
self.wordlistTableView.delegate = self.wordlistTableViewController;
self.wordlistTableView.datasource = self.wordlistTableViewController;
Those two lines both throw errors saying they can't find the properties 'delegate' nor 'datasource' on 'WSWordlistTableView*'. They're both there. I don't get it.
Related
In my viewcontroller like this:
#import "PPSharedView.h"
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
PPSharedView * sharedView = [[PPSharedView alloc] init];
sharedView.topImageName = #"fenxiangdao";
[sharedView sharedWithArrayImage:#[#"weixin_um",#"weixin_um",#"weixin_um",] titles:#[#"微信好友",#"微信好友",#"微信好友",]];
}
#end
In PPSharedView.h like this:
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#interface PPSharedView : UIView
-(void)sharedWithArrayImage:(nonnull NSArray *)arrImgs
titles:(nonnull NSArray *)arrTitles;
#end
In PPSharedView.m on the below:
-(void)sharedWithArrayImage:(NSArray *)arrImgs titles:(NSArray *)arrTitles{
if (arrImgs.count != arrTitles.count) return;
UIWindow * keyWindow = [UIApplication sharedApplication].keyWindow;
UIView * backView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, kSCREEN_W, kSCREEN_H)];
[keyWindow addSubview:backView];
backView.backgroundColor = [UIColor blackColor];
backView.alpha = 0.5;
UITapGestureRecognizer * tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(clickRedview)];
backView.userInteractionEnabled = YES;
[backView addGestureRecognizer:tap];
}
-(void)clickRedview{
NSLog(#"adf");
}
When I run the app on the iPhone the backView on the screen but can't response click events.Anyone knows what's wrong with the code?Thank you very much!
In controller the sharedView should be referenced example:
#interface ViewController ()
#property(nonatomic, strong) PPSharedView * ppView;
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
PPSharedView * sharedView = [[PPSharedView alloc] init];
self.ppView = sharedView;
sharedView.topImageName = #"fenxiangdao";
[sharedView sharedWithArrayImage:#[#"weixin_um",#"weixin_um",#"weixin_um",] titles:#[#"微信好友",#"微信好友",#"微信好友",]];
}
#end
If don't do this the sharedView will be destoryed!
I am learning ios with Stanford CS193P, and have issue in Lecture 8
I created a class named DropItBehavior inheritance from UIDynamicAnimator, but I can not use a UIDynamicAnimator method addChildBehavior,xcode warning like"No visible #interface for "DropItBehavior" declares the selector 'addChildBehavior'"
Here is the .h file
#import <UIKit/UIKit.h>
#interface DropItBehavior : UIDynamicAnimator
- (void)addItem:(id <UIDynamicItem>)item;
- (void)removeItem:(id <UIDynamicItem>)item;
#end
Here is the .m file
#import "DropItBehavior.h"
#interface DropItBehavior()
#property (strong, nonatomic) UIGravityBehavior *gravity;
#property (strong, nonatomic) UICollisionBehavior *collision;
#end
#implementation DropItBehavior
- (instancetype)init
{
self = [super init];
[self addChildBehavior:self.gravity];//Here is the Xcode warning"No visible #interface for "DropItBehavior" declares the selector 'addChildBehavior"
return self;
}
- (instancetype)init
{
self = [super init];
[self addChildBehavior:self.gravity];
return self;
}
- (UIGravityBehavior *)gravity
{
if (!_gravity) {
_gravity = [[UIGravityBehavior alloc] init];
_gravity.magnitude = 0.9;
}
return _gravity;
}
- (UICollisionBehavior *)collision
{
if (!_collision) {
_collision = [[UICollisionBehavior alloc] init];
_collision.translatesReferenceBoundsIntoBoundary = YES;
}
return _collision;
}
- (void)addItem:(id <UIDynamicItem>)item
{
[self.gravity addItem:item];
[self.collision addItem:item];
}
- (void)removeItem:(id <UIDynamicItem>)item
{
[self.gravity removeItem:item];
[self.collision removeItem:item];
}
#end
This is because addChildBehavior is a method of UIDynamicBehavior, not of UIDynamicAnimator. According to CS-193P's lecture notes, your DropIt class should inherit from UIDynamicBehavior instead:
#interface DropItBehavior : UIDynamicBehavior
Looking at the docs, there is no method -[UIDynamicAnimator addChildBehavior:], nor in your subclass.
However, UIDynamicBehavior does.
I would double check you are subclassing the right objects.
I'm adding a subview the following way"
SettingsViewController *SVC = [[SettingsViewController alloc] initWithNibName:#"SettingsViewController" bundle:[NSBundle mainBundle]];
[self.parentViewController addChildViewController:SVC];
[self.view addSubview:SVC.view];
My subview is 300 x 360 and is centered on the screen. The problem occurs when I attempt to remove it (Getting released).
When I press the close button in this new view, I get exc bad access. What's the correct way to add my view? I have a SettingsViewController.xib linked up to a .h and .m file.
Here's what my close button in my settings view looks like:
-(IBAction)close:(id)sender {
[self.view removeFromSuperview];
[self removeFromParentViewController];
}
But even when I comment out everything inside, just triggering the button crashes the app.
This is what my .h file looks like:
#import <UIKit/UIKit.h>
#interface SettingsViewController : UIViewController
#property (nonatomic, strong) IBOutlet UIView *alertView;
#property (nonatomic, strong) IBOutlet UIButton *closeButton;
#property (nonatomic, strong) IBOutlet UILabel *musicLabel;
#property (nonatomic, strong) IBOutlet UILabel *soundFXLabel;
#property (nonatomic, strong) IBOutlet UILabel *vibrateLabel;
- (IBAction)close:(id)sender;
#end
and my implementation file:
#import "SettingsViewController.h"
#interface SettingsViewController ()
#end
#implementation SettingsViewController
#synthesize alertView;
- (void)viewDidLoad
{
[super viewDidLoad];
self.view.alpha = 0;
self.alertView.layer.cornerRadius = 10.0f;
self.alertView.layer.borderColor = [UIColor whiteColor].CGColor;
self.alertView.layer.borderWidth = 4.0f;
self.closeButton.layer.cornerRadius = 5.0f;
self.closeButton.titleLabel.font = [UIFont fontWithName:#"SourceSansPro-Bold" size:20];
self.musicLabel.font = [UIFont fontWithName:#"SourceSansPro-Bold" size:30];
self.soundFXLabel.font = [UIFont fontWithName:#"SourceSansPro-Bold" size:30];
self.vibrateLabel.font = [UIFont fontWithName:#"SourceSansPro-Bold" size:30];
[UIView animateWithDuration:0.3
delay:0.0
options:UIViewAnimationOptionCurveEaseOut
animations:^{
self.view.alpha = 1;
}
completion:^(BOOL finished){
//Display Players View
}];
}
- (IBAction)close:(id)sender {
//[self.view removeFromSuperview];
//[self removeFromParentViewController];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
And last but not least, here's a snapshot of my storyboard / xib order:
create a property for your SettingsViewController where you add & assign it where you create it.
// in .h file or private category on top
#property (nonatomic, strong) SettingsViewController *settingsController;
// your usual code + assigning controller
SettingsViewController *SVC = [[SettingsViewController alloc] initWithNibName:#"SettingsViewController" bundle:[NSBundle mainBundle]];
[self.parentViewController addChildViewController:SVC];
[self.view addSubview:SVC.view];
self.settingsController = SVC;
Side Note : the reason for this behavior is after the .view property of the ViewController is added to your view, the controller gets deallocated (only the .view is alive now). So when you try to hit the butons on view there is no SettingsViewController to callback those events, hence crash. When you create the property & assign it, the controller lives.
I'm building a graphing app, and I have a view and a view controller, which acts as a delegate for the view (to retrieve information). While I haven't started the actual drawing yet, I am currently trying to store values in a dictionary; however, I have certain NSLogs placed methodically across the view controller and I noticed that the delegate methods I call from the view don't get called at all. For example, I call my scaleForGraph function, but it does not execute. Being new to this, I'm not sure if there's something I'm missing. FYI: I have no errors, it compiles and executes. I've tried to slim the code down as much as possible. Thank you for your help!
Here's the .h for my view, where I define the protocol:
// GraphView.h
#import <UIKit/UIKit.h>
#class GraphView;
#protocol GraphViewDelegate <NSObject>
- (float)scaleForGraph:(GraphView *)requestor;
-(NSMutableDictionary*) valuesForGraph:(GraphView *)requestor withWidth:(float) width;
#end
#interface GraphView : UIView
#property (nonatomic) id <GraphViewDelegate> delegate;
#property (nonatomic) id expressionCopy;
#end
And here's the .m:
#import "GraphView.h"
#implementation GraphView
#synthesize expressionCopy = _expressionCopy;
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
self.contentMode = UIViewContentModeRedraw;
}
return self;
}
- (void)awakeFromNib
{
self.contentMode = UIViewContentModeRedraw;
}
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect
{
CGContextRef c = UIGraphicsGetCurrentContext();
CGRect screenBound = [[UIScreen mainScreen] bounds];
CGSize screenSize = screenBound.size;
CGFloat width = screenSize.width;
CGFloat height = screenSize.height;
float scale = [self.delegate scaleForGraph:self];
NSLog([NSString stringWithFormat:#"My Scale: %f",scale]); //always returns 0
NSMutableDictionary *graphValues = [self.delegate valuesForGraph:self withWidth:width];
}
#end
And here's my view controller .h:
#import <UIKit/UIKit.h>
#import "GraphView.h"
#interface GraphingViewController : UIViewController <GraphViewDelegate>
#property (weak, nonatomic) IBOutlet GraphView *graphView;
#property (strong, nonatomic) IBOutlet UIStepper *stepper;
- (IBAction) changedScale:(UIStepper *)stepper;
#property (nonatomic) int scale;
#property (nonatomic) id expressionCopy;
#end
And here's the .m for the controller:
#import "GraphingViewController.h"
#interface GraphingViewController ()
#end
#implementation GraphingViewController
#synthesize expressionCopy = _expressionCopy;
- (void)updateUI
{
self.stepper.value = self.scale;
[self.graphView setNeedsDisplay];
}
- (void)setScale:(int)scale
{
if (scale < 0) scale = 0;
if (scale > 100) scale = 100;
_scale = scale;
[self updateUI];
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(IBAction)changedScale:(UIStepper *)stepper {
self.scale = stepper.value; //this function works fine, but is not delegate/does not get called by view
}
-(float) scaleForGraph:(GraphView *)requestor {
NSLog(#"HI"); //never gets here
}
-(NSMutableDictionary*) valuesForGraph:(GraphView *)requestor withWidth:(float) width {
NSLog(#"Hello2"); //never gets here
}
return xyVals;
}
#end
Nowhere in the code you've posted do you tell your GraphView that the GraphingViewController is it's delegate. So, you are sending a message to nil.
You'll want to do something like:
self.graphView.delegate = self;
In your GraphingViewController setup code.
Make your controller actual delegate of GraphView. You can do it in interface builder by Ctrl-dragging from GraphView to the object (orange circle in the bottom) and than choose "delegate"
I'm very new to iOS programming (Coming from Java / C++). I'm trying to set up an app with a TabBarController of which one tab should be a SplitView. I've done my research and I know that UISplitview will not work and everywhere people recommend using the MGSplitViewController. I've looked at the demo but I just can't figure out how to use it without it beeing the app's root view and can't find any sample code that could help
So here is what I do with the classes from the demo in a separate UIViewController class that I afterwards add to the TabBarController: This is my class:
#import <UIKit/UIKit.h>
#import "MGSplitCornersView.h"
#import "RootViewController.h"
#import "DetailViewController.h"
#interface ChannelViewController : UIViewController {
MGSplitViewController *splitViewController;
RootViewController *rootViewController;
DetailViewController *detailViewController;
}
#property (nonatomic, retain) MGSplitViewController *splitViewController;
#property (nonatomic, retain) RootViewController *rootViewController;
#property (nonatomic, retain) DetailViewController *detailViewController;
#end
And this is my desperate try to set it up
- (id)initWithTabBar
{
self = [super init];
//this is the label on the tab button itself
self.title = #"SplitView";
//use whatever image you want and add it to your project
//self.tabBarItem.image = [UIImage imageNamed:#"name_gray.png"];
// set the long name shown in the navigation bar at the top
self.navigationItem.title=#"Nav Title";
self.splitViewController = [[MGSplitViewController alloc] init];
self.rootViewController = [[RootViewController alloc] init];
self.detailViewController = [[DetailViewController alloc] init];
[self.splitViewController setDetailViewController:detailViewController];
[self.splitViewController setMasterViewController:rootViewController];
[self.view addSubview:splitViewController.view];
[self.rootViewController performSelector:#selector(selectFirstRow) withObject:nil afterDelay:0];
[self.detailViewController performSelector:#selector(configureView) withObject:nil afterDelay:0];
if (NO) { // whether to allow dragging the divider to move the split.
splitViewController.splitWidth = 15.0; // make it wide enough to actually drag!
splitViewController.allowsDraggingDivider = YES;
}
return self;
}
I guess I'm doing something wrong with delegates? Or do I have something else mixed up?
Is the demo doing things in the IB that I can't see in the code?
I get the split view but no content and especially no navigation bar with the buttons the demo comes with.
I'd be very thankful for hints or sample code!
Ok manny, here we go. This is my working code for the interface:
#import <UIKit/UIKit.h>
#import "MGSplitViewController.h"
#import "ecbView.h"
#import "ecbCalc.h"
#interface splitMain : MGSplitViewController <UIPopoverControllerDelegate,
MGSplitViewControllerDelegate>
{
IBOutlet UIPopoverController* popoverController;
IBOutlet UINavigationController* naviController;
IBOutlet ecbCalc* viewCalcLeft;
IBOutlet ecbView* euroRatesRight;
UIBarButtonItem* savedButtonItem;
BOOL keepMasterInPortraitMode;
BOOL memoryWasDropped;
BOOL viewLoaded;
}
#property (nonatomic, retain) UIPopoverController* popoverController;
#property (nonatomic, retain) UINavigationController* naviController;
#property (nonatomic, retain) ecbCalc* viewCalcLeft;
#property (nonatomic, retain) ecbView* euroRatesRight;
#property (nonatomic, retain) UIBarButtonItem* savedButtonItem;
#property (nonatomic, readonly) BOOL keepMasterInPortraitMode;
#property (nonatomic, readonly) BOOL memoryWasDropped;
#property (nonatomic, readonly) BOOL viewLoaded;
- (void)dismissPopoverController: (BOOL)animated;
- (void)settingsChanged;
#end
and here excerpts from implementation file:
- (id)initWithCoder:(NSCoder *)aDecoder
{
if ((self = [super initWithCoder:aDecoder]))
{
// my initialization...
}
return self;
}
// Implement loadView to create a view hierarchy programmatically, without using a nib.
- (void)loadView
{
CGRect rectFrame = CGRectMake(0.0, 20.0, 768.0, 1004.0 - 48.0); // being above a tab bar!
viewLoaded = NO;
self.view = [[UIView alloc] initWithFrame:rectFrame];
viewCalcLeft = [[ecbCalc alloc] initWithNibName:#"ecbCalc" bundle:nil];
euroRatesRight = [[ecbView alloc] initWithNibName:#"ecbView-iPad" bundle:nil];
naviController = [[UINavigationController alloc] initWithRootViewController:self.viewCalcLeft];
naviController.navigationBar.barStyle = UIBarStyleBlack;
naviController.title = nil;
viewCalcLeft.title = NSLocalizedString(#"BtnTitleCalc", #"");
viewCalcLeft.view.hidden = NO;
NSUserDefaults* prefs = [NSUserDefaults standardUserDefaults];
if ([prefs objectForKey:#"iPadAlwaysSplitTableView"] != nil)
self.keepMasterInPortraitMode = [prefs boolForKey:#"iPadAlwaysSplitTableView"];
else
self.keepMasterInPortraitMode = YES;
NSArray* theViewControllers = [NSArray arrayWithObjects:self.naviController, self.euroRatesRight, nil];
[self setViewControllers:theViewControllers];
[self setDelegate:self];
[self setShowsMasterInPortrait:keepMasterInPortraitMode];
}
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad
{
// protection because this one is called twice
if (viewLoaded)
return;
[super viewDidLoad];
if (memoryWasDropped)
{
if (!self.keepMasterInPortraitMode && UIInterfaceOrientationIsPortrait(self.interfaceOrientation))
{
// recreate popover controller
self.popoverController = [[UIPopoverController alloc] initWithContentViewController:self.viewCalcLeft];
}
}
viewLoaded = YES;
}
- (void)didReceiveMemoryWarning
{
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
memoryWasDropped = YES;
// Release any cached data, images, etc. that aren't in use.
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
[self dismissPopoverController:NO];
self.popoverController = nil;
self.naviController = nil;
self.viewCalcLeft = nil;
self.euroRatesRight = nil;
viewLoaded = NO;
}
My MainWindow.xib has a UITabBarController and the button for splitMain is configured for this class but with an empty xib entry. So creation has to go via loadView. Maybe I could have done the viewDidLoad stuff within loadView ... but so I had to protect viewDidLoad from being called twice. That happens in loadView as soon as the view is instantiated from MGSplitViewController class because the initWithCoder there is calling [self setup]. In that function the frame rect is calculated with self.view.bounds so that viewDidLoad is called again because the view doesn't exist yet. Maybe one could implement a workaround within MGSplitViewController.m but I was too lazy doing that.
To get this working on a tab bar controller please make sure you commit most of the changes that are published on the MGSplitViewController's git page. Good luck.