Greedy NSProgressIndicator Allocation - objective-c

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;
}

Related

How to return to the current scene when iAd is clicked

I am done with all the code for a sprite-Kit game, but iAd gave me lot of hard time. When iAd is clicked the game restarts again. How to fix this problem? I have the game with viewController , title Scene, levelOne Scene, level two scene. I read other related post but couldn't solve the issue. Thanks you.
viewController.h
#import <iAd/iAd.h>
#interface RAViewController
#property (nonatomic, strong) ADBannerView *adView;
#end
viewController.m
-(void)viewDidLoad{
ADBannerView *adView = [[ADBannerView alloc] initWithFrame:CGRectZero];
[adView setFrame:CGRectMake(0, 0, 1024, 768)]; // set to your screen dimensions
[adView setBackgroundColor:[UIColor clearColor]];
[self.view addSubview:adView];
}
adView = [[ADBannerView alloc] initWithFrame:CGRectZero];
adView.delegate = self;
[adView setFrame:CGRectMake(0, 0, 1024, 768)]; // set to your screen dimensions
[adView setBackgroundColor:[UIColor clearColor]];
[self.view addSubview:adView];
maybe delegate helps you. I didn't try this code, try it tell me if it works.

How should I go about recreating the iOS home screen open folder animation?

At first I thought it wouldn't be too hard, but turns out there's a bit more to it than I thought.
At the moment my code's based around this: https://github.com/jwilling/JWFolders. However, it's not very clean, the biggest problem being that it takes a screenshot every time the folder opens (renderInContext: is pretty taxing on the CPU so turns out being very low fps). Aside from that this implementation doesn't look as clean and as polished as the Apple animation does.
Apple manages to pull off a pixel perfect animation that doesn't lag. I'd like to do the same! What is the best way to go about this/how would you do this - a cleanly coded, good looking and fluid animation? At the moment, my animation's lacking in all those areas, and I'm stumped about how I could do it better (like Apple does it).
-
I'm not begging for code, just a best method/how to. But if you want to go ahead and code it then there's no way I'd say no (that would definitely be bouty worthy)!!
I would separate the Springboard into several views, where each view is one row of icons.
If a folder icon is clicked, I would animate all following views to move down and up to make place for the folder content. at the same time I would add a subview that represents the folder content and animates with the same speed its size and position if necessary.
To support a background image that spans over the whole screen I would cut that into pieces and add this pieces as background image views to each row's view.
I wrote a quick and dirty sample code with the animation starting on any tap location, also available as complete project on github.
#interface ViewController ()
#property (nonatomic, strong) UIView *upperView;
#property (nonatomic, strong) UIView *lowerView;
#property (nonatomic, strong) UIImageView *upperImageView;
#property (nonatomic, strong) UIImageView *lowerImageView;
#property (nonatomic, strong) UIView *folderContentsView;
#property (nonatomic, assign) CGRect startRect;
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
UIImage *bgImg = [UIImage imageNamed:#"bg.png"];
self.upperImageView = [[UIImageView alloc] initWithImage:bgImg];
self.lowerImageView = [[UIImageView alloc] initWithImage:bgImg];
[self.upperImageView setContentMode:UIViewContentModeTop];
[self.lowerImageView setContentMode:UIViewContentModeTop];
self.upperView = [[UIView alloc] initWithFrame:self.upperImageView.frame];
self.lowerView = [[UIView alloc] initWithFrame:self.lowerImageView.frame];
[self.upperView addSubview:_upperImageView];
[self.lowerView addSubview:_lowerImageView];
[self.view addSubview:_lowerView];
[self.view addSubview:_upperView];
UITapGestureRecognizer *upperTapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self
action:#selector(openOverlay:)];
UITapGestureRecognizer *lowerTapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self
action:#selector(openOverlay:)];
[self.upperView setUserInteractionEnabled:YES];
[self.upperView addGestureRecognizer:upperTapRecognizer];
[self.upperView setClipsToBounds:YES];
[self.lowerView setUserInteractionEnabled:YES];
[self.lowerView addGestureRecognizer:lowerTapRecognizer];
[self.lowerView setClipsToBounds:YES];
self.folderContentsView = [[UIView alloc] initWithFrame:CGRectZero];
self.folderContentsView.backgroundColor = [UIColor redColor];
UITapGestureRecognizer *closeTapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self
action:#selector(closeOverlay:)];
[self.folderContentsView addGestureRecognizer:closeTapRecognizer];
[self.view addSubview:self.folderContentsView];
[self.folderContentsView addSubview:[[UIImageView alloc] initWithImage:[UIImage imageNamed:#"bgFolder.png"]]];
[self.folderContentsView setClipsToBounds:YES];
self.startRect = [self.upperView frame];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
-(void)openOverlay:(UITapGestureRecognizer *) sender
{
[self.upperView setUserInteractionEnabled:NO];
[self.lowerView setUserInteractionEnabled:NO];
CGPoint location = [sender locationInView:sender.view];
self.folderContentsView.frame = CGRectMake(0, location.y,
_lowerView.frame.size.width, 0);
self.lowerView.frame = CGRectMake(0, location.y,
_lowerView.frame.size.width, _lowerView.frame.size.height);
self.upperView.frame = CGRectMake(0, 0,
_upperView.frame.size.width, location.y);
self.lowerImageView.frame = CGRectMake(_lowerImageView.frame.origin.x, -location.y,
_lowerImageView.frame.size.width, _lowerImageView.frame.size.height);
[UIView animateWithDuration:.5 animations:^{
self.folderContentsView.frame = CGRectMake(0, location.y,
_lowerView.frame.size.width, 200);
self.lowerView.frame = CGRectOffset(_lowerView.frame, 0, 200);
}];
}
-(void) closeOverlay:(UITapGestureRecognizer*) sender
{
[UIView animateWithDuration:.5 animations:^{
self.lowerView.frame = CGRectOffset(_lowerView.frame, 0, -200);
self.folderContentsView.frame = CGRectMake(0, self.folderContentsView.frame.origin.y,
self.folderContentsView.frame.size.width, 0);
} completion:^(BOOL finished) {
[self.upperView setUserInteractionEnabled:YES];
[self.lowerView setUserInteractionEnabled:YES];
self.upperView.frame = self.startRect;
}];
}
#end
two views a equipped with the same background in layers. If a tap is detected, both views are resized so that the upper view ends at the tap's y-coordinate, while the lower view starts there. the UIImageView added to the lowerView is moved in the opposite direction, so that the images stays in place.
Now the lowerView slides down while a contentView is added and resized at the same speed.
As you can see no image rendering or other tough action is required. just UIView animations.

Yet another custom UIView subclass

I would like to create a custom class by subclassing the UIView that would look like the one below:
Oh and the text says the body view should be 80px tall, its 50px.
But I cant seem to get it right. I have the class header prepared like so:
#import <UIKit/UIKit.h>
#interface MessageView : UIView
#property (strong, nonatomic)UIImage *backgroundImage;
#property (strong, nonatomic)UITextView *messageView;
#property (strong, nonatomic)UILabel *titleLabel;
- (id)initWithBackgroundImage:(NSString*)background;
- (void)setTitle:(NSString*)titleMessage;
- (void)setBody:(NSString*)bodyMessage;
#end
Now I will create these views by calling initWithBackgroundImage where I will pass the background image file name. The example shows one of these images. How do I implement the init method so that init will create a body like on the example except the texts will be empty?
My futile attempt of the init method was this:
- (id)initWithBackgroundImage:(NSString*)background
{
self = [super init];//[super initWithFrame:CGRectMake(0, 0, 270, 100)];
if (self)
{
backgroundImage = [[UIImage imageNamed:background] retain];
messageView = [[UITextView alloc] initWithFrame:CGRectMake(10, 40, 250, 50)];
titleLabel = [[UILabel alloc] initWithFrame:CGRectMake(10, 10, 250, 20)];
}
return self;
}
But nothing happened. When done I will set the text via setter methods. And I would like to set the position on the final view via setCenter(x, y). I want the class to have "fixed" width and height.
Thanks!
EDIT:
- (id)initWithBackgroundImage:(NSString*)background
{
self = [super init];//[super initWithFrame:CGRectMake(0, 0, 270, 100)];
if (self)
{
UIImageView *bg = [[UIImageView alloc] initWithImage:[UIImage imageNamed:background]];
messageView = [[UITextView alloc] initWithFrame:CGRectMake(10, 40, 250, 50)];
titleLabel = [[UILabel alloc] initWithFrame:CGRectMake(10, 10, 250, 20)];
[self addSubview:bg];
[bg release];
[self addSubview:messageView];
[messageView release];
[self addSubview:titleLabel];
[titleLabel release];
}
return self;
}

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

Cannot access properties of subclass

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.