I am trying to call a UIView FirstScreen from my ViewController.
But I don't know how to do it.
ViewController:
#import "ViewController.h"
#import "FirstScreen.h"
#interface ViewController ()
{
FirstScreen *f;
}
FirstScreen.m:
#import "FirstScreen.h"
#implementation FirstScreen
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
[self didLoad];
}
return self;
}
-(void) didLoad{
[self addLabel];
[self addImageView];
}
#implementation FirstScreen
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
[self didLoad];
}
return self;
}
-(void) didLoad
{
f = [[FirstScreen alloc] initWithFrame:CGRectMake(0, 0, self.view.size.width, self.view.size.height)];
[self.view addSubview:f];
}
#import "FirstScreen.h"
#implementation FirstScreen
-(instancetype)initWithFrame:(CGRect)frame{
self = [super initWithFrame:frame];
// calling another methods
[self anotherMethod];
return self;
}
-(void) anotherMethod
{
// write some code here
}
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
FirstScreenObj = [[FirstScreen alloc] initWithFrame:CGRectMake(0, 0, 200, 200)];
FirstScreenObj.backgroundColor = [UIColor grayColor];
[self.view addSubview:FirstScreenObj];
}
I hope it will help you!
Related
The title says it, I'd like to ask why the following does not work, as it should imho.
// ViewController.m
#import "B.h"
...
#implementation ViewController
{
B *bInstance;
}
- (instancetype)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
if (self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil])
{
bInstance = [[B alloc] initWithFrame:CGRectMake(0, 0, 200, 200)];
[bInstance setBlockCalled:^(NSDictionary *dict) {
NSLog(#"%#", dict[#"key"]);
}];
[self.view addSubview:bInstance];
}
return self;
}
// B.h
#import <UIKit/UIKit.h>
#interface B : UIView
#property (nonatomic, copy) void (^blockCalled)(NSDictionary *);
#end
// B.m
#import "B.h"
#import "A.h"
#implementation B
{
A *aInstance;
void (^blockCalled)(NSDictionary *);
}
#synthesize blockCalled;
- (instancetype)initWithFrame:(CGRect)frame
{
if (self = [super initWithFrame:frame])
{
aInstance = [[A alloc] initWithFrame:frame];
[aInstance setBlockCalled:blockCalled];
[self addSubview:aInstance];
}
return self;
}
#end
// A.h
#import <UIKit/UIKit.h>
#interface A : UIView
#property (nonatomic, copy) void (^blockCalled)(NSDictionary *);
#end
// A.m
#import "A.h"
#implementation A
{
void (^blockCalled)(NSDictionary *);
}
#synthesize blockCalled;
- (instancetype)initWithFrame:(CGRect)frame
{
if (self = [super initWithFrame:frame])
{
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
[button setFrame:CGRectMake(0, 0, 100, 100)];
[button setBackgroundColor:[UIColor redColor]];
[button addTarget:self action:#selector(buttonClicked) forControlEvents:UIControlEventTouchUpInside];
[self addSubview:button];
}
return self;
}
- (void) buttonClicked
{
blockCalled(#{#"key":#"value"});
}
#end
What I want to do is 'traverse up the view hiearchy', and as far as I see it, I'm assigning a block variable with the same arguments, so I'd expect it to work. Any reason why this is a wrong idea?
EDIT: added more complete example as of when this issue might happen.
EDIT2: added MCVE, which I've tested.
After I've checked the MCVE, the code crashes on the line blockCalled(#{#"key":#"value"}); in A.m because the blockCalled is nil.
Updated question: I'd like to know why calling [aInstance setBlockCalled:blockCalled] doesn't set the blockCalled in A, as it seems to me to be the same as
[aInstance setBlockCalled:^(NSDictionary *dict)
{
__strong typeof (self) strongSelf = self;
strongSelf.blockCalled(dict);
}];
#implementation ViewController
{
B *bInstance;
}
- (instancetype)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
if (self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil])
{
bInstance = [[B alloc] initWithFrame:CGRectMake(0, 0, 200, 200)];
[bInstance setBlockCalled:^(NSDictionary *dict) {
NSLog(#"%#", dict[#"key"]);
}];
[self.view addSubview:bInstance];
}
At the moment of initializing bInstance, you haven't set the block yet. It means
aInstance = [[A alloc] initWithFrame:frame];
[aInstance setBlockCalled:blockCalled];
is called before
[bInstance setBlockCalled:^(NSDictionary *dict) {
NSLog(#"%#", dict[#"key"]);
}];
You should override the block setter in B and call it on A.
// B.m
-(void)setBlockCalled(void(^)(NSDictionary*))passedBlock{
[a setBlockCalled:passedBlock];
}
The code in your question (a) uses ivars and #synthesize statements that are unnecessary; and (b) this code snippet is insufficient to reproduce the crash you describe.
Having said that, there are two possible source of crashes that are suggested by the code sample in the question, namely: (a) the code fails to remove the observer if A is deallocated; and (b) it really should double-check to make sure that blocks are non-nil before trying to call them.
But, consider the following:
// A.h
#interface A : UIView
#property (nonatomic, copy) void (^blockCalled)(NSDictionary *dict);
#end
// A.m
#implementation A
- (instancetype) initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(handleNotification:) name:#"kNotification" object:nil];
}
return self;
}
- (void)handleNotification:(NSNotification *)notification {
// never just call `blockCalled`; always check to see if not null
if (self.blockCalled) {
// everything is good, so let's call the block
self.blockCalled(notification.userInfo);
}
}
- (void)dealloc {
// never just `addObserver`; make sure to remove the observer when this is deallocated
[[NSNotificationCenter defaultCenter] removeObserver:self name:#"kNotification" object:nil];
}
#end
// B.h
#interface B : UIView
#property (nonatomic, copy) void (^blockCalled)(NSDictionary *dict);
#property (nonatomic, strong) A *aInstance;
#end
// B.m
#implementation B
- (void) someMethod {
// !!!!! why this crashes the app when blockCalled on aInstance is called:
[self.aInstance setBlockCalled:self.blockCalled];
// but this does not crash when the same happens
__weak typeof (self) weakSelf = self;
self.aInstance.blockCalled = ^(NSDictionary *dict) {
__strong typeof (self) strongSelf = weakSelf;
// again, never just call `blockCalled`; always check to see if not null
if (strongSelf.blockCalled) {
strongSelf.blockCalled(dict);
}
};
}
#end
Bottom line, when I fix the two obvious sources of crashes (failing to remove observer and failing to check to make sure the block was non-nil before calling it), and test it with logical scenario, it seems to work fine:
- (void)viewDidLoad {
[super viewDidLoad];
B *b = [[B alloc] init];
b.blockCalled = ^(NSDictionary *dict) {
NSLog(#"%#", dict);
};
A *a = [[A alloc] init];
b.aInstance = a;
[b someMethod];
[self.view addSubview:a];
[self.view addSubview:b];
NSDictionary *dict = #{#"foo": #"bar", #"baz": #"qux"};
[[NSNotificationCenter defaultCenter] postNotificationName:#"kNotification" object:nil userInfo:dict];
}
So, assuming one of these two issues wasn't the source of the problem, you must provide MCVE that we can use to reproduce the crash you describe.
I'm new to iOS programming and I need your help.
I am using UIsearchbar in our app but i want to separate the delegate of it.
I want to see the Nslog that i declare everytime I typed but it's returning an error :(
Heres my code.
//HomeController.h
#import <UIKit/UIKit.h>
#import "AsyncImageView.h"
#define kBgQueue dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)
#interface HomeController : UIViewController< UIScrollViewDelegate>
#end
//HomeController.m
SearchBarDelegate *searchDelegate = [[SearchBarDelegate alloc]init];
UISearchBar *searchBar = [[UISearchBar alloc] initWithFrame:CGRectMake(0, 20, 320, 44)];
searchBar.placeholder = #"Search here";
searchBar.layer.zPosition = 1000;
[self.view addSubview:searchBar];
searchBar setDelegate:searchDelegate];
//SearchBarDelegate.h
#import <UIKit/UIKit.h>
#interface SearchBarDelegate : UISearchBar<UISearchBarDelegate>
#end
//SearchBarDelegate.m
#import "SearchBarDelegate.h"
#implementation SearchBarDelegate
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
}
return self;
}
/*
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect
{
// Drawing code
}
*/
- (void)searchBarTextDidBeginEditing:(UISearchBar *)searchBars //Clicked the box
{
searchBars.showsCancelButton = YES;
}
- (void)searchBarCancelButtonClicked:(UISearchBar *)searchBars //hides searchBar and keyboard
{
searchBars.showsCancelButton = NO;
[searchBars resignFirstResponder];
}
- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBars //search button in keyboard
{
[searchBars resignFirstResponder];
}
- (void) searchBar:(UISearchBar*)searchBars textDidChange:(NSString*)searchText //while typing
{
NSLog(#"Typing... -> %#",searchBars.text);
}
#end
Let's see if you guys can find the error here... because I'm really stuck right now.
DBManager.h
#protocol DBManagerDelegate <NSObject>
#optional
- (void) managerDidFinishUpdating:(id)controller;
#end
#interface DBManager : NSObject
#property (strong, nonatomic) id <DBManagerDelegate> delegate;
- (id) init;
#end
DBManager.m
#import "DBManager.h"
#implementation DBManager
- (id)init {
self = [super init];
if (self) {
[[self delegate] managerDidFinishUpdating:self];
}
return self;
}
UIViewController.h
#import <UIKit/UIKit.h>
#import "DBManager.h"
#interface DBViewController : UIViewController <DBManagerDelegate>
#property (nonatomic, retain) DBManager *manager;
#end
UIViewController.m
#import "DBViewController.h"
#implementation DBViewController
- (void)viewDidLoad
{
[super viewDidLoad];
_manager = [[DBMataroManager alloc] init];
[_manager setDelegate:self];
}
- (void)managerDidFinishUpdating:(id)controller {
NSLog(#"Manager did finish");
}
#end
You should write like this,
- (id)initWithDelegate:(id)delegate {
self = [super init];
if (self) {
_delegate = delegate;
[_delegate managerDidFinishUpdating:self];
}
return self;
}
//Call it as follow
_manager = [[DBManager alloc] initWithDelegate:self];
[_manager setDelegate:self];
The delegate method managerDidFinishUpdating: is called within init. You set yourself as the delegate after calling init.
Maybe an initWithDelegate: method would help.
- (instancetype)initWithDelegate:(id< DBManagerDelegate>)delegate {
self = [super init];
if (self) {
self.delegate = delegate;
[self.delegate managerDidFinishUpdating:self];
}
return self;
}
You are trying to use the delegate in the init, but you have not set it until the next statement. The only way to do this would be to set the delegate as part of you init statement.
-(id)initWithDelegate:(id<DBManageDelegate>)delegate {
if ((self = [super init])) {
self.delegate = delegate;
if (delegate && [delegate respondsToSelector:#selector(managerDidFinishUpdating:)]) {
[delegate performSelector:#selector(managerDidFinishUpdating:) withObject:self];
}
}
return self;
}
But if you plan to do some additional things before the manager is updated I would suggest you move all of that outside of the init, perhaps into an updateManager function like this
-(void)updateManager {
// Do the stuff that updates your manager here
if (delegate && [delegate respondsToSelector:#selector(managerDidFinishUpdating:)]) {
[delegate performSelector:#selector(managerDidFinishUpdating:) withObject:self];
}
}
..later in your app
_manager = [[DBMataroManager alloc] init];
[_manager setDelegate:self];
[_manager updateManager];
I'm trying to structure some view-code out of the controller (obviously without using a nib). Therefore, I tried a simple example, but for some reason, I can't add the target to the button in the controller, rest is fine. Here's what I'm trying:
Controller.h:
#import <UIKit/UIKit.h>
#import "IndexView.h"
#interface IndexController : UIViewController
{
}
#property (nonatomic) IndexView *contentView;
#end
Controller.m
#import "IndexController.h"
#import "IndexView.h"
#interface IndexController ()
#end
#implementation IndexController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
self.contentView = [[IndexView alloc]init];
[self.view addSubview:self.contentView];
[self connectUIElements];
}
return self;
}
- (void) connectUIElements
{
[self.contentView.testButton addTarget:self action:#selector(testButtonClicked) forControlEvents:UIControlEventTouchUpInside];
}
#pragma mark --
#pragma mark UIHandler
- (void) testButtonClicked
{
NSLog(#"testbutton clicked");
}
#end
View.h
#import <UIKit/UIKit.h>
#interface IndexView : UIView
#property (nonatomic, strong) UIButton *testButton;
#end
View.m
#import "IndexView.h"
#implementation IndexView
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
[self setUpView];
}
return self;
}
- (id) init
{
self = [super init];
if (self) {
[self setUpView];
}
return self;
}
- (void) setUpView
{
[self setBackgroundColor:[UIColor whiteColor]];
self.testButton = [[UIButton alloc]initWithFrame:CGRectMake(10, 50, 100, 50)];
self.testButton.backgroundColor = [UIColor greenColor];
[self.testButton setTitle:#"hello, world" forState:UIControlStateNormal];
[self addSubview:self.testButton];
}
#end
I'm just exploring possibilities to get closer to a classical MVC pattern and a little farther away from Apples mediator-interpretation. Any idea what's wrong?
You have to create your view using initWithFrame:, which is the default initializer for UIView. (The reason that is does not work with a simple init - but I am guessing here! - might be that the views size is zero and therefore the touch events do not work.)
after try 2 days and i'm losing my mind now... the main problem is simple.. i've button in uiview,, and i want to call method on uiviewcontroller ... here's the code
Uiview call headerView.h
#class HeaderView;
#protocol headerViewDelegate
- (void)tes:(HeaderView *)tes ratingDidChange:(float)rating;
#end
#interface HeaderView : UIView {
UIButton *test;
}
#property (nonatomic,strong) UIButton *test;
#property (assign) id <headerViewDelegate> delegate;
#end
and the Headerview.M
#import "HeaderView.h"
#import <QuartzCore/QuartzCore.h>
#implementation HeaderView
#synthesize test;
- (id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame]; // not needed - thanks ddickison
if (self) {
test=[UIButton buttonWithType:UIButtonTypeRoundedRect];
test.frame=CGRectMake(30, 10, 100,40);
[test setTitle:#"Kampret" forState:UIControlStateNormal];
[test addTarget:self action:#selector(testdata:) forControlEvents:UIControlEventTouchUpInside];
}
[self addSubview:test];
return self;
}
- (id)initWithCoder:(NSCoder *)aDecoder {
if ((self = [super initWithCoder:aDecoder])) {
}
return self;
}
- (void)dealloc {
[super dealloc];
}
-(void)layoutSubviews{
self.backgroundColor=[UIColor whiteColor];
[self release]; // release object before reassignment to avoid leak - thanks ddickison
//self = [nib objectAtIndex:0];
self.layer.shadowColor = [[UIColor blackColor] CGColor];
self.layer.shadowOffset = CGSizeMake(1.0, 1.0);
self.layer.shadowOpacity = 0.40;
}
-(void)testdata:(id)sender{
[self.delegate tes:self ratingDidChange:1.1f];
}
#end
viewcontroller.h
#import <UIKit/UIKit.h>
#import "HeaderView.h"
#interface ReusableTableHeadersViewController : UITableViewController <headerViewDelegate> {
HeaderView *header;
}
#property(nonatomic,strong) HeaderView *header;
#end
viewcontroller.m
#import "viewcontroller.h"
#implementation ReusableTableHeadersViewController
#synthesize header;
#synthesize tblData, data;
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad {
[super viewDidLoad];
header = [[HeaderView alloc] initWithFrame:CGRectMake(0, 0, 320, 120)];
[self.view addSubview:header];
}
- (void)didReceiveMemoryWarning {
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
}
- (void)dealloc {
[super dealloc];
}
-(void)tes:(HeaderView *)tes ratingDidChange:(float)rating{
NSLog(#"passing data==========%f",rating);
}
#end
i want to log the rating :
NSLog(#"passing data==========%f",rating);
from method:
-(void)testdata:(id)sender{
[self.delegate tes:self ratingDidChange:1.1f];
}
but it show nothing... why? because i use initwithframe?
dont blame me... i'm totally newbie here :)
You have not set delegate of headerview as view controller.
- (void)viewDidLoad {
[super viewDidLoad];
header = [[HeaderView alloc] initWithFrame:CGRectMake(0, 0, 320, 120)];
header.delegate = self;
[self.view addSubview:header];
}