I currently have a custom timer class and a custom UITableviewCell, the timer has a set of delegate methods that fire based on the timer state, the custom cell has an instance of this timer class as a property and has the delegate methods set in the M file, however i notice they are not firing when the cell is assigned a timer and the timer is started.. my code is as follows:
TABLEVIEW CELL H
#import <UIKit/UIKit.h>
#import "TimerClass.h"
#interface AeroPressCell : UITableViewCell <timerDelegate>
#property (weak, nonatomic) IBOutlet UILabel *centerLabel;
#property (weak, nonatomic) IBOutlet UILabel *rightLabel;
#property (weak, nonatomic) IBOutlet UILabel *bottomLabel;
#property (weak, nonatomic) IBOutlet UIImageView *cellImage;
#property (weak, nonatomic) IBOutlet TimerClass *timer;
TABLEVIEW CELL M
#import "AeroPressCell.h"
#implementation AeroPressCell
#synthesize cellImage;
#synthesize centerLabel;
#synthesize bottomLabel;
#synthesize rightLabel;
#synthesize timer;
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
// Initialization code
}
return self;
}
- (void)setSelected:(BOOL)selected animated:(BOOL)animated
{
[super setSelected:selected animated:animated];
// Configure the view for the selected state
}
#pragma mark Timer Delegate
#pragma mark -
- (void)timerStarted{
NSLog(#"STARTED");
}
- (void)timerTick{
}
- (void)timerPaused{
NSLog(#"PAUSED");
}
- (void)timerResumed{
}
- (void)timerFinished{
NSLog(#"FINISHED");
}
#end
I know that these delegate methods work as i have tested by using an instance of this timer class in a viewcontroller and it's firing, is this not possible with a uitable view cell? Currently the timers are counting down in each cell but the delegate methods do not fire, any idea whats happening?
In your AeroPressCell code, you haven't set the delegate of the timer class to the cell's instance. Try setting the timer's delegate like so - self.timer.delegate = self.
Related
I have a custom class called NumberView which subclasses UIScrollView. I put a UIView onto my storyboard and changed the class to NumberView:
I then created an outlet to my ShotTraceViewController class:
#interface ShotTraceViewController ()
#property (weak, nonatomic) IBOutlet NumberView *numberView;
#end
I've defined a few methods in the NumberView.h and NumberView.m:
.h:
#interface NumberView : UIScrollView
#property (weak, nonatomic) id<NumberViewDelegate> number_delegate;
-(void)setTotalBtns:(int)total;
...
#end
.m:
#interface NumberView ()
#end
#implementation NumberView {
}
-(instancetype)initWithFrame:(CGRect)frame{
self = [super initWithFrame:frame];
return self;
}
-(instancetype)initWithCoder:(NSCoder *)aDecoder{
self = [super initWithCoder:aDecoder];
return self;
}
-(void)setTotalBtns:(int)total {
NSLog(#"Setting buttons");
}
#end
But when I try to call [self.numberView setTotalBtns:3]; from my ShotTraceViewController. I get an exception:
-[UIView setTotalBtns:]: unrecognized selector sent to instance 0x104fad3e0
Whoa! That's not right, it's supposed to be a NumberView not a UIView! Am I doing something wrong?
I've also noticed that initWithFrame and initWithCoder are both not being called.
I don't know why this worked, but unchecking the Inherit Module from Target button underneath the class selection fixed everything.
In my iOS application, I have a main View Controller with three buttons, which work like a tab bar: when I click one of the buttons, a new view controller is invoked.
I tried to implement this via container view containers, so I tried following this guide (http://www.thinkandbuild.it/working-with-custom-container-view-controllers/) and invoke the presentDetailController method in the viewDidLoad of the main controller.
Actually, no views are showed: someone can help me figuring out why? Thanks.
ViewController.h
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController
#property (weak, nonatomic) IBOutlet UIButton *btnOne;
#property (weak, nonatomic) IBOutlet UIButton *btnTwo;
#property (weak, nonatomic) IBOutlet UIButton *btnThree;
#property (weak, nonatomic) IBOutlet UIView *detailView;
- (IBAction)click:(id)sender;
#end
ViewController.m
#import "ViewController.h"
#import "FirstViewController.h"
#interface ViewController ()
#property UIViewController *currentDetailViewController;
#end
#implementation ViewController
#synthesize btnOne, btnTwo, btnThree;
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
FirstViewController *fvc = [[FirstViewController alloc]initWithString:#"I'm the first Controller!"];
[self presentDetailController:fvc];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)click:(id)sender
{
// button selection stuff
[self addDetailController:sender];
}
- (void)presentDetailController:(UIViewController*)detailVC{
//0. Remove the current Detail View Controller showed
if(self.currentDetailViewController){
[self removeCurrentDetailViewController];
}
//1. Add the detail controller as child of the container
[self addChildViewController:detailVC];
//2. Define the detail controller's view size
detailVC.view.frame = [self frameForDetailController];
//3. Add the Detail controller's view to the Container's detail view and save a reference to the detail View Controller
[self.detailView addSubview:detailVC.view];
self.currentDetailViewController = detailVC;
//4. Complete the add flow calling the function didMoveToParentViewController
[detailVC didMoveToParentViewController:self];
}
- (void)removeCurrentDetailViewController{
//1. Call the willMoveToParentViewController with nil
// This is the last method where your detailViewController can perform some operations before neing removed
[self.currentDetailViewController willMoveToParentViewController:nil];
//2. Remove the DetailViewController's view from the Container
[self.currentDetailViewController.view removeFromSuperview];
//3. Update the hierarchy"
// Automatically the method didMoveToParentViewController: will be called on the detailViewController)
[self.currentDetailViewController removeFromParentViewController];
}
- (CGRect)frameForDetailController{
// newFrame's height should be currentFrame's height minus buttons' height
CGRect detailFrame = CGRectMake(0, 0, self.detailView.bounds.size.width, self.detailView.bounds.size.height-self.btnOne.frame.size.height);
return detailFrame;
}
- (void)addDetailController:(id)sender {
FirstViewController *detailVC = [[FirstViewController alloc]initWithString:#"First button clicked"];
[self presentDetailController:detailVC];
}
#end
FirstViewController.h
#import <UIKit/UIKit.h>
#class ViewController;
#interface FirstViewController : UIViewController
#property (weak, nonatomic) IBOutlet UILabel *label;
#property (weak, nonatomic) IBOutlet UIButton *btnOne;
#property (weak, nonatomic) IBOutlet UIButton *btnTwo;
#property (weak, nonatomic) IBOutlet UIButton *btnThree;
- (id)initWithString:(NSString*)string;
#end
FirstViewController.m
#import "FirstViewController.h"
#interface FirstViewController (){
NSString *text;
}
#end
#implementation FirstViewController
- (id)initWithString:(NSString*)string {
self = [super init];
if(self){
text = string;
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
self.label.text = text;
}
#end
As part of creating FirstViewController, you are calling [super init] which produces a bare UIViewController. From your diagram, it seems as if you want to load a FirstViewController from your storyboard instead.
I suggest a sequence where you create your controller using instantiateViewControllerWithIdentifier:, then set a string property in the controller that you want to use as the label, and finally assign the string to the label when the controller's view loads.
I have a custom UIButton class like below :
.h
#import <UIKit/UIKit.h>
#class FriendButton;
#protocol LongPressedButtonDelegate
- (void)buttonIsLongPressed:(FriendButton *)button;
#end
#interface FriendButton : UIButton
#property (nonatomic, weak) id<LongPressedButtonDelegate > delegate;
#end
.m
#implementation FriendButton
//this is called from the interface builder
-(id) initWithCoder:(NSCoder *)aDecoder {
self = [super initWithCoder:(NSCoder *)aDecoder];
NSLog(#"init called");
UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc]initWithTarget:self action:#selector(longPress:)];
[self addGestureRecognizer:longPress];
return self;
}
-(void)longPress:(id)sender {
NSLog(#"long press");
[self.delegate buttonIsLongPressed:self];
}
#end
My buttons are set up in the interface builder, they are contained in a UITableView cell. In my UITableViewController I have :
-(void)buttonIsLongPressed:(FriendButton *)button {
NSLog(#"Delegate method!");
}
and it controller conforms to protocol. The long press gesture works but the delegate method is not being called. I'm not sure why it's not working. Is it because I have to set each buttons delegate to the UITableViewController? If so how would I do that? The buttons are set up in the interface builder.
Define your UIButton property this way
#interface FriendButton : UIButton
#property (nonatomic, weak) IBOutlet id<LongPressedButtonDelegate > delegate;
#end
Then go to Interface Builder and right click on UIButton and you will see delegate link this delegate to UITableViewController. It should work
In your cellForRowAtIndexPath implementation in your UITableViewController you will need to do something like:
cell.button.delegate = self;
Edit: This is if you want to do it programmatically. Refer to the answers around IBOutlets if you want to do it in your storyboard.
I have a parent view controller with a single method I want available to all child classes:
#import "GAViewController.h"
#interface GAViewController ()<UITextFieldDelegate>
#end
#implementation GAViewController
#pragma mark - UITextFieldDelegate
- (BOOL)textFieldShouldReturn:(UITextField *)textField
{
[textField resignFirstResponder];
return YES;
}
#end
I have a register view controller which looks like this:
//.h
#import <UIKit/UIKit.h>
#import "GAViewController.h"
#import "GAViewController.m"
#interface GARegisterViewController : GAViewController
#end
//.m
#import "GARegisterViewController.h"
#interface GARegisterViewController ()<UIActionSheetDelegate, UINavigationControllerDelegate, UIImagePickerControllerDelegate, UIGestureRecognizerDelegate>
#property (weak, nonatomic) IBOutlet UIButton *registerButton;
#property (weak, nonatomic) IBOutlet UITextField *userNameTextField;
#property (weak, nonatomic) IBOutlet UITextField *passwordTextField;
#property (weak, nonatomic) IBOutlet UITextField *firstNameTextField;
#property (weak, nonatomic) IBOutlet UITextField *lastNameTextField;
#property (weak, nonatomic) IBOutlet UITextField *phoneNumberTextField;
#property (weak, nonatomic) IBOutlet UISegmentedControl *genderSegmentedContoller;
#end
#implementation GARegisterViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
[self makeTextFieldDelegates];
}
- (void)makeTextFieldDelegates{
[self.userNameTextField setDelegate:self];
[self.passwordTextField setDelegate:self];
[self.firstNameTextField setDelegate:self];
[self.lastNameTextField setDelegate:self];
[self.phoneNumberTextField setDelegate:self];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
Here is the error I receive:
Does anyone know I can either fix the error above? Or create a parent class correctly with the textFieldShoudlReturn method so that I don't have to include in all my views.
Thanks!
I am importing .m because it contains the textfieldshouldreturn method, it also imports the .h file
It is importing .m file that causes duplicate symbols. Importing a .m file causes the file from which it is imported to define the same symbols (such as method implementations and functions / variables with external scope) as the .m file being included, causing the duplication.
For the same reason one should never place #implementation blocks into header files.
In order to fix this, make a header for GAViewController, and declare textFieldShouldReturn: inside it. Remove #import "GAViewController.m" from your headers and .m files, replacing with #import "GAViewController.h". This should fix the problem.
"* Assertion failure in -[PlayingCell layoutSublayersOfLayer:],
/SourceCache/UIKit_Sim/UIKit-2372/UIView.m:5776 2013-11-01
18:44:12.526 SnapTrack[216:c07] * Terminating app due to uncaught
exception 'NSInternalInconsistencyException', reason: 'Auto Layout
still required after executing -layoutSubviews. PlayingCell's
implementation of -layoutSubviews needs to call super.'"
I'm trying to run my app (which I designed for iOS7) in the iOS6 simulator. My project contains a TabBarController. In the first view controller in the tabbarcontroller I have a table view containing custom UITableViewCell's. They load without a problem. However, when I switch to another tab, where I have another table view, also with custom cells, I get the error posted above. The viewControllers are set up almost identically (both have subviews organized with auto layout). Has anyone seen this exception/know how to address it?
Thanks!
EDIT: Code for PlayingCell.
#import <UIKit/UIKit.h>
#interface PlayingCell : UITableViewCell
#property (strong, nonatomic) IBOutlet UILabel *lblTrackNum;
#property (strong, nonatomic) IBOutlet UIImageView *albumArt;
#property (strong, nonatomic) IBOutlet UILabel *lblSongTitle;
#property (strong, nonatomic) IBOutlet UILabel *lblAlbumTitle;
#property (strong, nonatomic) IBOutlet UILabel *lblArtist;
#property (strong, nonatomic) IBOutlet UIImageView *imgPlay;
#property (strong,nonatomic) NSMutableDictionary *songInfo;
- (IBAction)downloadBtnPressed:(id)sender;
#end
#import "PlayingCell.h"
#implementation PlayingCell
#synthesize songInfo;
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
// Initialization code
}
return self;
}
- (void)setSelected:(BOOL)selected animated:(BOOL)animated
{
[super setSelected:selected animated:animated];
// Configure the view for the selected state
}
- (IBAction)downloadBtnPressed:(id)sender
{
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:[songInfo objectForKey:#"trackViewUrl"]]];
NSLog(#"%#",[songInfo objectForKey:#"trackViewUrl"]);
}
-(void)layoutSubviews
{
[super layoutSubviews];
}
Do what the error states. In one of your custom cell classes you appear to be overriding the layoutSubviews method. You must call [super layoutSubviews] in your implementation. This is typically the 1st line.
- (void)layoutSubviews {
[super layoutSubviews];
// the rest of your custom layout code
}