Cannot access properties of subclass - objective-c

I have created the following subclass to do some custom drawing:
// DocumentIconView.h
#interface DocumentIconView : UIView
{
UIImageView *documentIconView;
CloseHandle *closeHandle;
UILabel *filenameLabel;
}
#property (nonatomic, strong) UIImageView *documentIconView;
#property (nonatomic, strong) CloseHandle *closeHandle;
#property (nonatomic, strong) UILabel *filenameLabel;
+ (DocumentIconView *)documentIconWithFrame:(CGRect)viewFrame
previewImage:(UIImage *)previewImage
title:(NSString *)title;
This works well for the most part (I can instantiate objects, and do custom drawing), however, I cannot access some of its properties from another classes.
DocumentIconView *iconView = [DocumentIconView documentIconWithFrame:frame
previewImage:[UIImage imageNamed:#"GenericDocumentIcon.png"]
title:[NSString stringWithFormat:#"test"]];
iconView.backgroundColor = [UIColor lightGrayColor]; // this works
iconView.filenameLabel.backgroundColor = [UIColor darkGrayColor]; // this does not work - no error message
[documentsView addSubview:iconView];
I can read and write first-level properties, but cannot drill deeper; when trying to read properties, the value returned is (null)
I am fairly new at subclassing, so I think I am missing something really obvious here. Any help would be greatly appreciated.
EDIT: the method for instantiating the view in question:
+ (DocumentIconView *)documentIconWithFrame:(CGRect)viewFrame
previewImage:(UIImage *)previewImage
title:(NSString *)title
{
DocumentIconView *view = [[DocumentIconView alloc] initWithFrame:viewFrame];
// Close handle's size is assigned here
CGSize closeHandleSize = CGSizeMake(27, 27);
// The document preview image's frame is calculated by shrinking it by the close handle's size
CGRect documentPreviewFrame = CGRectMake(closeHandleSize.width / 2,
closeHandleSize.height / 2,
viewFrame.size.width - closeHandleSize.width,
viewFrame.size.height - closeHandleSize.height - 20); // 20 points is the filenameLabel's height
UIImageView *documentPreviewView = [[UIImageView alloc] initWithFrame:documentPreviewFrame];
documentPreviewView.contentMode = UIViewContentModeScaleAspectFit;
documentPreviewView.backgroundColor = [UIColor clearColor];
documentPreviewView.image = previewImage;
[view addSubview:documentPreviewView];
CGRect closeHandleFrame = CGRectMake(0, 0, closeHandleSize.width, closeHandleSize.height);
CloseHandle *closeHandleView = [[CloseHandle alloc] initWithFrame:closeHandleFrame];
closeHandleView.alpha = 0.0;
closeHandleView.tag = kCloseHandleTag;
[view addSubview:closeHandleView];
CGRect filenameFrame = CGRectMake(0,
viewFrame.size.height - 20,
viewFrame.size.width,
20);
UILabel *filenameLabel = [[UILabel alloc] initWithFrame:filenameFrame];
filenameLabel.backgroundColor = [UIColor clearColor];
filenameLabel.text = title;
filenameLabel.font = [UIFont boldSystemFontOfSize:17];
filenameLabel.textColor = [UIColor whiteColor];
filenameLabel.textAlignment = UITextAlignmentCenter;
[view addSubview:filenameLabel];
view.tag = kDocumentIconTag;
return view;
}

In your documentIconWithFrame:... method you're using a local variable (filenameLabel) that you're adding to the view. That means your instance variable is never instantiated and is always nil.
Just change this:
UILabel *filenameLabel = [[UILabel alloc] initWithFrame:filenameFrame];
to this:
filenameLabel = [[UILabel alloc] initWithFrame:filenameFrame];
and the same for the other instance variables.

Related

objective-c adding UILabel to center

hi i'm begginer in objective-c and i want to learn how i can make UILabel in center of screen
this is my code:
XXRootViewController.h
#interface XXRootViewController : UIViewController{
UILabel *title; } #end
XXRootViewController.m
#import "XXRootViewController.h"
#implementation XXRootViewController {
NSMutableArray *_objects;
}
- (void)loadView {
[super loadView];
self.view = [[[UIView alloc]
initWithFrame:[[UIScreen mainScreen] applicationFrame]]
autorelease];
self.view.backgroundColor = [UIColor whiteColor];
title = [[UILabel alloc] initWithFrame:CGRectMake(300,200,400,200)];
title.text = #"This is Sasuke's first app :)";
[self.view addSubview:title];
}
#end
Try this code i make some changes in you code
self.view = [[UIView alloc]
initWithFrame:[UIScreen mainScreen].bounds];
self.view.backgroundColor = [UIColor whiteColor];
title = [[UILabel alloc] initWithFrame:CGRectMake(0,0,[UIScreen mainScreen].bounds.size.width - 50,200)];
title.text = #"This is Sasuke's first app :)";
title.textAlignment = NSTextAlignmentCenter;
title.center = self.view.center;
[self.view addSubview:title];
You just need to set frame in center of the screen ...
change your one line code with it -
title = [[UILabel alloc] initWithFrame:CGRectMake(self.view.frame.size.width/2 - 200,self.view.frame.size.height/2 - 100,400,200)];
now your label is shown in the center of screen .. This will help you change the frame according to your use...
Has Hardik Thakkar said, the best way would be to use the center method. That way, even if your label would grow, it will always be centred.
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(300,200,400,200)];
label.text = #"something";
label.center = self.view.center; (this should always be you superview)
Now, even if your label is bigger than the size you were expecting, it will always be centred

Xcode is showing a warning about unsafe_unretained and not sure on how to fix this

MDRadialProgressTheme *newTheme = [[MDRadialProgressTheme alloc] init];
newTheme.completedColor = [UIColor whiteColor];
newTheme.incompletedColor =[UIColor darkGrayColor]; //[UIColor colorWithRed:177/255.0 green:179/255.0 blue:181/255.0 alpha:1.0];
newTheme.centerColor = [UIColor clearColor];
//newTheme.centerColor = [UIColor colorWithRed:219/255.0f green:220/255.0f blue:221.0 alpha:1.0f];
newTheme.sliceDividerHidden = YES;
newTheme.labelColor = [UIColor blackColor];
newTheme.labelShadowColor = [UIColor whiteColor];
CGRect frame = CGRectMake(0,0, 45, 45);
radialView = [[MDRadialProgressView alloc] initWithFrame:frame andTheme:newTheme]; // warning here
// Assigning retained object to unsafe_unretained variable; object will be released after assignment
radialView.center=CGPointMake(self.bounds.size.width / 2.0f, self.bounds.size.width / 2.0f);
radialView.progressTotal = 4;
radialView.clockwise =YES;
radialView.label.hidden =YES;
radialView.progressCounter = 1;
[self addSubview:radialView];
I get a warning on the line radialView = [[MDRadialProgressView saying Assigning retained object to unsafe_unretained variable; object will be released after assignment
What does it mean and how do I fix it?
#property (nonatomic,assign) MDRadialProgressView *radialView;
radialView is declared in the header (see above)
Change your property to
#property (nonatomic, strong) MDRadialProgressView *radialView;

Greedy NSProgressIndicator Allocation

I'm using a bunch of NSProgressIndicators at once (32 to be exact) and it looks like when they're animating they start allocating memory like no one's business
I've got reports that the app will slowdown and eventually crash after days of uptime, and this looks like the most likely culprit, but it's hard to pinpoint bugs that take days to appear.
I simply comment out the call to start animating, all memory behaves as expected. Could this be a result of multiple NSProgressIndicators alloc'ed on the same thread? or maybe sandboxing? All of the constant allocations are coming from Core Animation threads, I don't know what else could be going on.
Custom NSView that the progress indicator lives in
#interface MyView ()
#property (nonatomic, strong) NSImageView *imageView;
#property (nonatomic, strong) NSTextView *numberTxt;
#property (nonatomic, strong) NSProgressIndicator *progress;
#end
#implementation MyView
- (id)initWithFrame:(NSRect)frameRect {
self = [super initWithFrame:frameRect];
if (self) {
// Image
NSImage *image = [NSImage imageNamed:#"bg.png"];
CGRect rect = CGRectMake(0, 0, image.size.width, image.size.height);
self.imageView = [[NSImageView alloc] initWithFrame:NSRectFromCGRect(rect)];
self.imageView.image = image;
[self addSubview:self.imageView];
// Number
CGRect numberRect = CGRectMake(0, 30, image.size.width, 40);
self.numberTxt = [[NSTextView alloc] initWithFrame:NSRectFromCGRect(numberRect)];
[self.numberTxt setBackgroundColor:[NSColor clearColor]];
[self.numberTxt setEditable:NO];
[self.numberTxt setFont:[NSFont systemFontOfSize:30]];
[self.numberTxt setTextColor:[NSColor redColor]];
[self addSubview:self.numberTxt];
// Progress
CGRect progressRect = CGRectMake(self.frame.size.width * 0.5 - 20, self.frame.size.height * 0.5 - 20, 40, 40);
self.progress = [[NSProgressIndicator alloc] initWithFrame:NSRectFromCGRect(progressRect)];
[self.progress setStyle:NSProgressIndicatorSpinningStyle];
//This line, when commented, fixes things
[self.progress startAnimation:self];
//
[self addSubview:self.progress];
}
return self;
}

Custom UIButton not capturing touches after adding subview

I've got a UIButton declared in interface builder with an outlet set as follows:
#property (weak, nonatomic) IBOutlet UIButton *loginButton;
It works fine until I insert a subview. Then it stops responding. Here's the offending line:
[self.loginButton insertSubview:_gradientButtonView atIndex:0];
Commenting that out makes the button work again. Here's all the code involved (using the awesome SSToolkit and a custom category on UIColor):
SSGradientView *_gradientButtonView = [[SSGradientView alloc] initWithFrame:self.loginButton.layer.bounds];
_gradientButtonView.autoresizingMask = UIViewAutoresizingFlexibleWidth;
_gradientButtonView.topBorderColor = [UIColor colorWithRed:0.558f green:0.599f blue:0.643f alpha:1.0f];
_gradientButtonView.topInsetColor = [UIColor colorWithWhite:1.0f alpha:0.3f];
_gradientButtonView.colors = [NSArray arrayWithObjects:[UIColor from_hex:#"E6E7E8"], [UIColor from_hex:#"A7A9AC"], nil];
_gradientButtonView.layer.cornerRadius = 5;
self.loginButton.layer.cornerRadius = 5;
self.loginButton.titleLabel.shadowOffset = CGSizeMake(0, 1);
[self.loginButton setTitleShadowColor:[UIColor whiteColor] forState:UIControlStateNormal];
self.loginButton.layer.masksToBounds = YES;
_gradientView.bottomBorderColor = [UIColor colorWithRed:0.428f green:0.479f blue:0.520f alpha:1.0f];
_gradientButtonView.clipsToBounds = YES;
_gradientButtonView.userInteractionEnabled = YES;
[self.loginButton insertSubview:_gradientButtonView atIndex:0];
self.loginButton.userInteractionEnabled = YES;
This was answered in the comments above:
Is there a specific reason you're writing
_gradientButtonView.userInteractionEnabled = YES;? To my knowledge, this prevents the view from sending touch events up the responder
chain

Objective C implementing a UIPickerView with a "Done" button

I am trying to implement a "Done" button in a UIPickerView Similar to the one under this link
I looked in the class reference but I couldn t find it
Thanks
The easiest way to do it is to model it in Interface Builder. It is a UIView containing a UIToolbar and a UIPickerView.
Then create an outlet for the UIView and connect it.
If you then have a UITextField you can assign your custom view to its inputView property.
[self.textField setInputView:self.customPicker];
Alternatively you can add the picker to your main view...
- (void)viewDidLoad
{
[super viewDidLoad];
self.customPicker.frame = CGRectMake(0, CGRectGetMaxY(self.view.frame), CGRectGetWidth(self.customPicker.frame), CGRectGetHeight(self.customPicker.frame));
[self.view addSubview:self.customPicker];
}
... and then use this method to show or hide the picker.
- (void)setPickerHidden:(BOOL)hidden
{
CGAffineTransform transform = hidden ? CGAffineTransformIdentity : CGAffineTransformMakeTranslation(0, -CGRectGetHeight(self.customPicker.frame));
[UIView animateWithDuration:0.3 animations:^{
self.customPicker.transform = transform;
}];
}
I added a UIToolbar with a UIBarButtonItem for the 'done' button in my xib with the frame set so that it's not initially visible (y value equal to the height of the parent view).
Every time the user access the picker, I changed the frame (the y value) of the UIDatePicker and the UIToolbar with an animation so that it slides up along with the picker from the bottom of the screen similar to the keyboard.
Check out my code below.
- (IBAction)showPicker
{
if(pickerVisible == NO)
{
// create the picker and add it to the view
if(self.datePicker == nil) self.datePicker = [[[UIDatePicker alloc] initWithFrame:CGRectMake(0, 460, 320, 216)] autorelease];
[self.datePicker setMaximumDate:[NSDate date]];
[self.datePicker setDatePickerMode:UIDatePickerModeDate];
[self.datePicker setHidden:NO];
[self.view addSubview:datePicker];
// the UIToolbar is referenced 'using self.datePickerToolbar'
[UIView beginAnimations:#"showDatepicker" context:nil];
// animate for 0.3 secs.
[UIView setAnimationDuration:0.3];
CGRect datepickerToolbarFrame = self.datePickerToolbar.frame;
datepickerToolbarFrame.origin.y -= (self.datePicker.frame.size.height + self.datePickerToolbar.frame.size.height);
self.datePickerToolbar.frame = datepickerToolbarFrame;
CGRect datepickerFrame = self.datePicker.frame;
datepickerFrame.origin.y -= (self.datePicker.frame.size.height + self.datePickerToolbar.frame.size.height);
self.datePicker.frame = datepickerFrame;
[UIView commitAnimations];
pickerVisible = YES;
}
}
- (IBAction)done
{
if(pickerVisible == YES)
{
[UIView beginAnimations:#"hideDatepicker" context:nil];
[UIView setAnimationDuration:0.3];
CGRect datepickerToolbarFrame = self.datePickerToolbar.frame;
datepickerToolbarFrame.origin.y += (self.datePicker.frame.size.height + self.datePickerToolbar.frame.size.height);
self.datePickerToolbar.frame = datepickerToolbarFrame;
CGRect datepickerFrame = self.datePicker.frame;
datepickerFrame.origin.y += (self.datePicker.frame.size.height + self.datePickerToolbar.frame.size.height);
self.datePicker.frame = datepickerFrame;
[UIView commitAnimations];
// remove the picker after the animation is finished
[self.datePicker performSelector:#selector(removeFromSuperview) withObject:nil afterDelay:0.3];
}
}
I create a custom class, this supports multiple orientation:
DateTimePicker.h
#interface DateTimePicker : UIView {
}
#property (nonatomic, assign, readonly) UIDatePicker *picker;
- (void) setMode: (UIDatePickerMode) mode;
- (void) addTargetForDoneButton: (id) target action: (SEL) action;
#end
DateTimePicker.m
#define MyDateTimePickerToolbarHeight 40
#interface DateTimePicker()
#property (nonatomic, assign, readwrite) UIDatePicker *picker;
#property (nonatomic, assign) id doneTarget;
#property (nonatomic, assign) SEL doneSelector;
- (void) donePressed;
#end
#implementation DateTimePicker
#synthesize picker = _picker;
#synthesize doneTarget = _doneTarget;
#synthesize doneSelector = _doneSelector;
- (id) initWithFrame: (CGRect) frame {
if ((self = [super initWithFrame: frame])) {
self.backgroundColor = [UIColor clearColor];
UIDatePicker *picker = [[UIDatePicker alloc] initWithFrame: CGRectMake(0, MyDateTimePickerToolbarHeight, frame.size.width, frame.size.height - MyDateTimePickerToolbarHeight)];
[self addSubview: picker];
UIToolbar *toolbar = [[UIToolbar alloc] initWithFrame: CGRectMake(0, 0, frame.size.width, MyDateTimePickerToolbarHeight)];
toolbar.barStyle = UIBarStyleBlackOpaque;
toolbar.autoresizingMask = UIViewAutoresizingFlexibleWidth;
UIBarButtonItem *doneButton = [[UIBarButtonItem alloc] initWithTitle: #"Done" style: UIBarButtonItemStyleBordered target: self action: #selector(donePressed)];
UIBarButtonItem* flexibleSpace = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil];
toolbar.items = [NSArray arrayWithObjects:flexibleSpace, doneButton, nil];
[self addSubview: toolbar];
self.picker = picker;
picker.autoresizingMask = UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight|UIViewAutoresizingFlexibleTopMargin|UIViewAutoresizingFlexibleBottomMargin;
self.autoresizesSubviews = YES;
self.autoresizingMask = UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight|UIViewAutoresizingFlexibleTopMargin|UIViewAutoresizingFlexibleBottomMargin;
}
return self;
}
- (void) setMode: (UIDatePickerMode) mode {
self.picker.datePickerMode = mode;
}
- (void) donePressed {
if (self.doneTarget) {
[self.doneTarget performSelector:self.doneSelector withObject:nil afterDelay:0];
}
}
- (void) addTargetForDoneButton: (id) target action: (SEL) action {
self.doneTarget = target;
self.doneSelector = action;
}
Using custom view in your view controller:
- (void)viewDidLoad
{
[super viewDidLoad];
UIButton *button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[button addTarget:self
action:#selector(buttonPressed:)
forControlEvents:UIControlEventTouchDown];
[button setTitle:#"Show picker" forState:UIControlStateNormal];
button.frame = CGRectMake(100, 50, 100, 40.0);
[self.view addSubview:button];
CGRect screenRect = [[UIScreen mainScreen] bounds];
CGFloat screenWidth = screenRect.size.width;
CGFloat screenHeight = screenRect.size.height;
picker = [[DateTimePicker alloc] initWithFrame:CGRectMake(0, screenHeight/2 - 35, screenWidth, screenHeight/2 + 35)];
[picker addTargetForDoneButton:self action:#selector(donePressed)];
[self.view addSubview:picker];
picker.hidden = YES;
[picker setMode:UIDatePickerModeDate];
}
-(void)donePressed {
picker.hidden = YES;
}
-(void)buttonPressed:(id)sender {
picker.hidden = NO;
}
Hope this helps. :)
There is a more elegant solution. I'm not sure if this is recent (as of iOS7), but this has been working for me splendidly.
TJDatePicker.h
#protocol TJDatePickerActionDelegate <NSObject>
- (void)cancel:(id)sender;
- (void)done:(id)sender;
#end
#interface TJDatePicker : UIDatePicker
#property (strong, nonatomic) UIView *navInputView;
#property (weak, nonatomic) id<TJDatePickerActionDelegate> actionDelegate;
#end
TJDatePicker.m
#import "TJDatePicker.h"
#interface TJDatePicker ()
#property (strong, nonatomic) TJButton *cancelButton;
#property (strong, nonatomic) TJButton *doneButton;
#end
#implementation TJDatePicker
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self)
{
[self updateSubviews];
}
return self;
}
- (void)layoutSubviews
{
[super layoutSubviews];
[self updateSubviews];
}
- (void)updateSubviews
{
self.navInputView.frame = CGRectMake(0, 0, self.width, 45);
self.cancelButton.frame = CGRectMake(5, 5, 80, 35);
CGFloat width = 80;
self.doneButton.frame = CGRectMake(CGRectGetMaxX(self.navInputView.frame) - width, self.cancelButton.frame.origin.y, width, self.cancelButton.height);
}
- (UIView *)navInputView
{
if (!_navInputView)
{
_navInputView = [[UIView alloc] init];
_navInputView.backgroundColor = [UIColor whiteColor];
self.cancelButton = [UIButton buttonWithType:UIButtonTypeCustom];
[self.cancelButton setTitle:#"CANCEL" forState:UIControlStateNormal];
[self.cancelButton addTarget:self action:#selector(cancelButtonPressed) forControlEvents:UIControlEventTouchUpInside];
[_navInputView addSubview:self.cancelButton];
self.doneButton = [UIButton buttonWithType:UIButtonTypeCustom];
[self.doneButton setTitle:#"DONE" forState:UIControlStateNormal];
[self.doneButton addTarget:self action:#selector(doneButtonPressed) forControlEvents:UIControlEventTouchUpInside];
[_navInputView addSubview:self.doneButton];
}
return _navInputView;
}
- (void)cancelButtonPressed
{
[self.actionDelegate cancel:self];
}
- (void)doneButtonPressed
{
[self.actionDelegate done:self];
}
And then at implementation time...
self.datePicker = [[TJDatePicker alloc] init];
self.datePicker.actionDelegate = self;
self.textField.inputAccessoryView = self.datePicker.navInputView;
The key here is to use the inputAccessoryView of the UITextField that you are planning on setting the UIDatePicker to.
You get the "Done" button in the toolbar using the ActionSheetPicker. Its is a great alternative to building it yourself.
https://github.com/skywinder/ActionSheetPicker-3.0
Success! Ok, I would never suggest doing this, but here's where the done button is created in your particular tutorial code:
Looking at the storyboard, we can see that when you click the "Role" box within "AddPersonTVC.h" (class at the top right of the storyboard), it pops up a class called "RollPickerTVCell.h"
Looking into RollPickerTVCell.h, we notice that the whole class is a subclass of "CoreDataTableViewCell"
#interface RolePickerTVCell : CoreDataTableViewCell <UIPickerViewDataSource, UIPickerViewDelegate>
Looking at the class "CoreDataTableViewCell.m", we finally find our uibarbuttonitem!
UIBarButtonItem *doneBtn =[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:#selector(done:)];
In case you are working on a Table View Cell and you are not using a UITextField (hence you won't be using the Accessory View), here's what I did:
I created a table view cell called GWDatePickerCell that looks like this (no .nib files involved).
GWDatePickerCell.h:
#import <UIKit/UIKit.h>
#interface GWDatePickerCell : UITableViewCell
#property (nonatomic, strong) UIDatePicker *datePicker;
#property (nonatomic, strong) UIToolbar *toolbar;
#property (nonatomic, strong) UIBarButtonItem *buttonDone;
#end
GWDatePickerCell.m:
#import "GWDatePickerCell.h"
#implementation GWDatePickerCell
- (id) initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
if(!(self=[super initWithStyle:style reuseIdentifier:reuseIdentifier])) return nil;
_datePicker = [[UIDatePicker alloc] init];
[_datePicker setMinuteInterval:5];
[_datePicker setDatePickerMode:UIDatePickerModeDateAndTime];
[self.contentView addSubview:_datePicker];
_toolbar = [[UIToolbar alloc] init];
_buttonDone = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:nil action:nil];
_toolbar.items = #[[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil], _buttonDone];
[self.contentView addSubview:_toolbar];
return self;
}
- (void)layoutSubviews{
[super layoutSubviews];
CGRect r = self.contentView.bounds;
r.origin.y +=44;
r.size.height = 216;
CGRect tb = self.contentView.bounds;
tb.size.height = 44;
_datePicker.frame = r;
_toolbar.frame = tb;
}
#end
Now all I had to do when creating the cells in the Table View:
Specify the #selector for the Done button.
Set the correct cell height in heightForRowAtIndexPath