I created a UITableView programmatically, but none of its methods were called. I must have missed something:
- (void)viewDidLoad
{
[super viewDidLoad];
...
self.transactionView = [[UITableView alloc] initWithFrame:CGRectMake(0.0, CARD_VIEW_Y, 320.0, CARD_VIEW_H)];
self.transactionView.delegate = self;
[self.view addSubview:self.transactionView];
You need to wire both the delegate AND the dataSource of the tableview. UITableViewDataSource provides the methods to fill the actual table with data.
Related
I have an xib file containing a custom cell. I'm trying to access the height of an object created in customCell.m.
Here is my code:
customCell.m
- (void)awakeFromNib
{
self.label = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 50, 200)];
[self.label setText:#"This is a label"];
[self.myView addSubview:self.label];
NSLog(#"%f", self.label.frame.size.height); // Results: 200.0000
}
mainViewController.m
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
customCell *cellVC = [[cutsomCell alloc] init];
NSLog(#"%f, %f", cellVC.label.frame.size.height); // Results: 0.0000
}
awakeFromNib is called when all file owners outlets and properties are set. Things are not wired up (in terms of frames/layout) in viewDidLoad.
awakeFromNib is called after viewDidLoad, that is why you see the difference.
Sorry, this doesn't work. You are creating your customCell via alloc/init in code. AwakeFromNib is only called for objects defined in a nib file.
You probably need to define your customCell in a separate nib file, and load that nib file through + (BOOL)loadNibNamed:(NSString *)aNibName owner:(id)owner or similar.
I have an app with several SKScenes. To keep it snappy, I have a single UIViewController, that handles 1 SKView.
I'm trying to add a UICollectionView to one of the SKScenes. However the problem comes when I try to set the delegate for the collection view to the SKScene initialising it.
I initialise it here:
- (id)initWithSize:(CGSize)size
{
if (self = [super initWithSize:size]) {
//Initialise collectionView
UICollectionViewLayout *layout = [[UICollectionViewLayout alloc] init];
_collectionView = [[UICollectionView alloc] initWithFrame:CGRectMake(0, 0, size.width, size.height) collectionViewLayout:layout];
_collectionView.delegate = self;
_collectionView.dataSource = self;
[_collectionView setBackgroundColor:[UIColor redColor]];
}
return self;
}
After initialising, I add the collection view as a subview of the UIViewController's view by calling:
- (void)didMoveToView:(SKView *)view
{
[self.view addSubview:_collectionView];
}
But the delegate or datasource methods aren't called. I've set up the header:
#interface BrowseScene : SKScene <UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout>
I'm guessing that despite setting self as the delegate, once the collection view is added, it is added as a subview of the UIViewController's SKView, and therefore has no reference to the SKScene that initialised it. I tried calling:
_collectionView.delegate = self.view.scene;
But I get a compiler error saying SKScene is an incompatible type for UICollectionViewDelegate.
So my question is, how best to approach this?
It turns out, the problem lay in how I was initialising the UICollectionView, not where. And it's perfectly ok to set an SKScene as the delegate class.
The main reason the delegates weren't being called was because I'd initialised the collectionView with an empty layout object (as UICollectionViewLayout is just an abstract class). I initialised with a standard UICollectionViewFlowLayout instead, and the methods were then called when the class initialised.
I was also missing a call to
[_collectionView registerClass:[collectionViewCell class] forCellWithReuseIdentifier:#"collectionViewCell"];
(In the complete code, I had calls to reloadData, so that wasn't the problem here).
It might be helpful to know that I come from a iOS background and that this is one of my first OS X projects.
In my project, I have a NSView subclass and a NSViewController and load the view in the controller.
- (void)loadView
{
StartView *view = [StartView alloc] initWithFrame:frame]; // frame exists
self.view = view;
}
The view has a NSButton-property btnNewthat I add in initWithFrame:.
- (id)initWithFrame:(NSRect)frame
{
self = [super initWithFrame:frame];
if (self) {
self.btnNew = [[NSButton alloc] initWithFrame:NSRectFromCGRect(CGRectMake(350, 180, 300, 60))];
[self addSubview:self.btnNew];
}
return self;
}
In loadView: I try to set the action and target.
- (void)loadView
{
StartView *view = [StartView alloc] initWithFrame:frame]; // frame exists
[view.btnNew setTarget:self];
[view.btnNew setAction:#selector(createNew:)];
self.view = view;
}
The createNew: function exists, off course.
However, when clicking the button, the app crashes. When I move the setTarget: and the setAction: into the view and perform them on self.btnNew, it works, but I think that's not how you should work with events and user interaction in a decent MVC-architecture.
The problem is with the self in [view.btnNew setTarget:self];, I guess. If I grab the target with view.btnNew.target, this is a nil object (0x000…000). Self exists & view.btnNew exists.
Am I doing something wrong? Or should I really listen to the click in the view and work with a delegate or a notification (I guess not?)
I found it out myself, with help from Niel Deckx.
The problem was ARC. The ViewController got dealloced before the click happened, which explains the NSObject does not respond to selector: the target doesn't exist anymore.
The easy solution is to have the ViewController as a (strong?) property where you create it.
I'm working on a custom implementation of UISegmentedControl.
I'd like to create a component that able to receive config data and from which obtain a custom View similar to UISegmentedControl.
I started subclassing a UIView and i can create a custom UISegmentedControl with this code:
CustomSegment *segment = [[CustomSegment alloc]
initWithTitles:[NSArray arrayWithObjects:#"one",#"two",nil]];
[self.window addSubview:segment];
But now i'd like to improve my class and add some more customizable parameters to it.
For example i'd like add a custom separators, define the button fonts and so on... here my doubt:
Is it better to work on a UIView subClass or you suggest me to subclass a UIViewController, where i can manage View hierarchy in method like -(void)loadView and -(void)viewDidLoad ?
In a simple UIView subclass, when i launch the custom init method, i setup immediately subviews... while using a UIViewController i can call custom init and define how my subview is builded into -(void)loadView.
Don't use an UIViewController, just extend the UIView class like you did and keep extending its functionality.
Remember to save a pointer to each subview you add (i.e. buttons) in order to be able to access them later.
Define custom setters, for example, a custom setter for changing a button label title would be:
- (void) setButton1Title:(NSString*)str forState:(UIControlState)state{
//You can add some control here
if ([str length] > 20) return;
[_button1 setTitle:str forState:state]; //_button1 is my reference to the button
}
And so on. Don't provide direct access to your subviews, use methods instead.
Also, you can use "layoutSubviews" method to define how your views are going to be displayed in your custom view.
Hope it helps you.
Edit: In your case, I don't see why using lauoutSubviews method but I want to show you what I was trying to say.
Lets say that for example I need to create an UIView class to represent a "Contact" object in my application.
This is what I would do:
#interface ContactView : UIView{
UILabel* _nameLabel;
UILabel* _ageLabel;
Contact* _contact;
}
#property (retain) Contact* contact;
#end
#implementation ContactView
#synthetize contact = _contact;
-(id)initWithContact:(Contact*)c{
self = [super init];
if (self) {
_nameLabel = [[UILabel alloc] init];
_nameLabel.frame = CGRectZero;
[self addSubview:_nameLabel];
[_nameLabel release];
_ageLabel = [[UILabel alloc] init];
_ageLabel.frame = CGRectZero;
[self addSubview:_ageLabel];
[_ageLabel release];
self.contact = c;
}
}
- (void) layoutSubviews{
[super layoutSubviews];
_nameLabel.frame = CGRectMake(0.0f, 0.0f, 200.0f, 25.0f);
_ageLabel.frame = CGRectMake(0.0f, 25.0f, 200.0f, 25.0f);
if (self.contact){
_nameLabel.text = self.contact.name;
_ageLabel.text = self.contact.age;
}else{
_nameLabel.text = #"Unavailable";
_ageLabel.text = #"Unavailable";
}
}
- (void) setContact:(Contact*)c{
self.contact = c;
[self layoutSubviews];
}
#end
Check out how the "layoutSubiews" is used to set the correct frame and data to the labels.
Usually, I use it a lot when creating custom UITableViewCells where you have to reuse the view.
Let me know if I'm being confusing.
I have four buttons, which have to push the same uiTableViewController, with different data in every case. I think I need to implement an initializer for my table and pass a NSArray. and then I'll check which button is pushed with the sender property.
Is that ok? How can I implement this initializer? I searched in the doc but I haven't get solution yet.
in your view controller you can initialize tableview by [UITableView alloc] initWithFrame:self.view.bounds]; and put this initialization in viewdidload method of your view controller,you don't need xib now.
to be specific use
[self.tableView = [UITableView alloc] initWithFrame:self.view.bounds];
self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
self.tableView.backgroundColor = [UIColor colorWithRed:0.96 green:0.96 blue:0.96 alpha:1.000];
self.tableView.bounces=YES;
[self.view addSubview:self.tableView];
self.tableView.delegate = self;
self.tableView.dataSource = self;