Using a block in Object-C, I get "Thread 1:EXC_BAD_ACCESS(code=1,address=0x0)" - objective-c

I want to add GestureRecognizer on an imageView and use a block in the clickAction.
But when I run it, I get this error in the block:
Thread 1:EXC_BAD_ACCESS(code=1,address=0x0)
#import "blockImage.h"
#implementation blockImage
-(instancetype)init{
if (self = [super init]) {
self = [[blockImage alloc]initWithFrame:CGRectMake(100, 100, 100, 100)];
self.tag = 10;
self.backgroundColor = [UIColor redColor];
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc]initWithTarget:self action:#selector(tapActionWithBolck:)];
[self addGestureRecognizer:tap];
}
return self;
}
-(void)tapActionWithBolck:(void(^)(NSInteger idx))completion{
completion(10);
}
#end
and
#import "ViewController.h"
#import "blockImage.h"
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
blockImage *img = [[blockImage alloc] init];
[self.view addSubview:img];
}
#end

You can not use method like this with UITapGestureRecognizer
-(void)tapActionWithBolck:(void(^)(NSInteger idx))completion;
it should be like that
-(void)tapAction:(UIGestureRecognizer *)sender;
or
-(void)tapAction;
If you want to use block on tap, you should keep it in variable (in init for example) and than call it in method. But keep in mind about retain cycles.

Related

Add UITapGestureRecognizer to UIVIew XIB

#interface MyCustomView() #end
#implementation MyCustomView
- (instancetype)init {
self = [[[MyClass bundle] loadNibNamed:kOverlayNib owner:self options:nil] firstObject];
self.layer.cornerRadius = 10;
self.translatesAutoresizingMaskIntoConstraints = NO;
self.userInteractionEnabled = YES;
UITapGestureRecognizer *singleFingerTap =
[[UITapGestureRecognizer alloc] initWithTarget:self
action:#selector(handleSingleTap:)];
[singleFingerTap setNumberOfTapsRequired:1];
[singleFingerTap setNumberOfTouchesRequired:1];
[self addGestureRecognizer:singleFingerTap];
return self; }
//The event handling method
- (void)handleSingleTap:(UITapGestureRecognizer *)recognizer {
NSLog(#"Tappedddddddddd");
}
I have added Tap Gesture Recognizer to my kOverlayNib.xib but for some reason i can not get any response.. It is not working at all..
you missed some things..
#interface MyCustomView() <UIGestureRecognizerDelegate> #end or anywhere you want to write.
singleFingerTap.delegate = self;
- (BOOL)gestureRecognizer:(UIGestureRecognizer )gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer)otherGestureRecognizer { return YES; }
Now you can run your code. it works.

UIButton not respond in UIView

UIButton in my view does not respond when I click it. Some one figure
out what I am doing wrong? Here is my entire code:
MyView.h
#interface Myview : UIView
#end
MyView.m
#import "MyView.h"
- (init){
self = [super init];
if(self)
[self createButton];
return self;
}
- (void) createButton{
UIButton *button = [[UIButton alloc] initWithFrame:CGRectMake(100,100,100,50)];
[button setTitle:#"Go" forState:UIControlStateNormal];
[button addTarget:self
`action:#selector(goAction)
forControlEvents:UIControlEventTouchUpInside];
[self addSubview:button];
}
- (void) goAction{
NSString *test = #"Some text";
}
MyViewController.m
- (id) init{
self = [super init];
if (self) {
MyView *myview = [[MyView alloc] init];
[self.view addSubview:myview];
}
return self;
}`
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
}
ViewController.m
#import "ViewController.h"
#import "MyViewController.h"
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
MyViewController *myTestView = [[MyViewController alloc] init];
[self.view addSubview:myTestView.view];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
The reason why clicks does not work is that you don't set frame of MyView
This way it works (although I still don't understand why you need to add one ViewController into another)
#implementation MyViewController
- (instancetype)init
{
self = [super init];
if (self) {
MyView *myview = [[MyView alloc] init];
myview.frame = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.width);
[self.view addSubview:myview];
}
return self;
}

Understanding how UIPickerView works

fairly new, and I would need a hand understanding UIPickerViews.
I have created a UIPickerView programmatically for my project:
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
UIPickerView *myPickerView = [[UIPickerView alloc] initWithFrame:CGRectMake(0, 200, 375, 200)];
myPickerView.delegate = self;
myPickerView.showsSelectionIndicator = YES;
[self.view addSubview:myPickerView];
}
And then added a method for the number of rows:
- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component {
NSUInteger numRows = 5;
return numRows;
}
Which returns as expected five question marks. I could then go on to create an array to fill those rows etc... but instead I next add another UIPickerView like so:
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
UIPickerView *myPickerView = [[UIPickerView alloc] initWithFrame:CGRectMake(0, 200, 375, 200)];
myPickerView.delegate = self;
myPickerView.showsSelectionIndicator = YES;
[self.view addSubview:myPickerView];
UIPickerView *my2PickerView = [[UIPickerView alloc] initWithFrame:CGRectMake(0, 400, 375, 200)];
my2PickerView.delegate = self;
my2PickerView.showsSelectionIndicator = YES;
[self.view addSubview:my2PickerView];
}
- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component {
NSUInteger numRows = 5;
return numRows;
}
Now I have two pickerview controllers and they BOTH have five rows. My question is how do chose to which pickerview the method applies and also could anyone explain why does the method apply to all pickerviews in the project? Thanks.
You only have one delegate method for two PickerViews ; that's something I don't like with iOS but you don't really have a choice here.
You have to if-statement yourself out of this.
The pickerView parameter in the delegate method is the pickerview that is being assigned the number of rows.
Note that this is valid for any of the usual delegate methods for iOS, wether it's the numberOfRows of your pickerview, or your tableview, or your collectionView, or any delegate method that has the view in parameter.
The easy understandable way is to have your pickerview as fields of your class (or properties), and simply compare the parameter with it.
#interface ViewController ()
#property (weak, nonatomic) UIPickerView *_mySexyPickerView;
#property (weak, nonatomic) UIPickerView *_myOtherPickerView;
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
_mySexyPickerView = [[UIPickerView alloc] initWithFrame:CGRectMake(0, 200, 375, 200)];
_mySexyPickerView.delegate = self;
_mySexyPickerView.showsSelectionIndicator = YES;
[self.view addSubview:_mySexyPickerView];
_myOtherPickerView = [[UIPickerView alloc] initWithFrame:CGRectMake(0, 400, 375, 200)];
_myOtherPickerView.delegate = self;
_myOtherPickerView.showsSelectionIndicator = YES;
[self.view addSubview:_myOtherPickerView];
}
- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component {
if (pickerView == _mySexyPickerView){
return 2;
}
if (pickerView == _myOtherPickerView){
return 19;
}
return 0;
}

How do I call a method from my uiviewcontroller in a utility nsobject class

How do I import a method from my uiviewcontroller to a utility class of nsobject (which I use in the viewcontroller to call common methods?) I have a large number of view controllers that need to call the same method.
Do I need to use NSInvocation? Should I use something different like protocols and delegates?
Without access to the method by the utility class I will just get "NSInvalidArgumentException"
This is the basic structure I need to use.
utilityClass - .h
#import <Foundation/Foundation.h>
#interface utilityClass : NSObject
- (void) swipeLoad: (UIView*)myview;
#end
.m
#import "utilityClass.h"
#implementation utilityClass
- (void) swipeLoad: (UIView*) myview
{
UISwipeGestureRecognizer *oneFingerSwipeRight =
[[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(oneFingerSwipeRight:)];
[oneFingerSwipeRight setDirection:UISwipeGestureRecognizerDirectionRight];
[myview addGestureRecognizer:oneFingerSwipeRight];
UISwipeGestureRecognizer *oneFingerSwipeLeft =
[[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(oneFingerSwipeLeft:)];
[oneFingerSwipeLeft setDirection:UISwipeGestureRecognizerDirectionLeft];
[myview addGestureRecognizer:oneFingerSwipeLeft];
UISwipeGestureRecognizer *twoFingerSwipeRight =
[[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(twoFingerSwiperight:)];
[twoFingerSwipeRight setDirection:UISwipeGestureRecognizerDirectionRight];
twoFingerSwipeRight.numberOfTouchesRequired = 2;
[myview addGestureRecognizer:twoFingerSwipeRight];
UISwipeGestureRecognizer *twoFingerSwipeLeft =
[[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(twoFingerSwipeLeft:)];
[twoFingerSwipeLeft setDirection:UISwipeGestureRecognizerDirectionLeft];
twoFingerSwipeLeft.numberOfTouchesRequired = 2;
[myview addGestureRecognizer:twoFingerSwipeLeft];
}
#end
view controller - .h
#import <UIKit/UIKit.h>
#import "utilityClass.h"
#class utilityClass;
#interface viewController : UIViewController
{
utilityClass *utilityClass;
}
#property (nonatomic, retain) utilityClass*utilityClass;
#end
.m
#import "viewcontroller.h"
#interface viewcontroller ()
#end
#implementation viewcontroller
#synthesize utilityClass = _utilityClass;
- (void)viewDidLoad
{
[super viewDidLoad];
self.utilityClass = [[utilityClass alloc] init];
[self.utilityClass swipeLoad:self.view];
}
- (void)twoFingerSwiperight:(UISwipeGestureRecognizer *)recognizer {
//[self another_method]
}
- (void)twoFingerSwipeLeft:(UISwipeGestureRecognizer *)recognizer {
//[self another_method]
}
- (void)oneFingerSwipeRight:(UISwipeGestureRecognizer *)recognizer {
//[self another_method]
}
- (void)oneFingerSwipeLeft:(UISwipeGestureRecognizer *)recognizer {
//[self another_method]
}
#end
It sounds like you would be better off subclassing UIViewController and putting your swipe methods in there. Then make all of your view controllers a subclass of your new subclass (in the example below, your view controllers would be subclasses of MyViewController.
You would then get rid of your utility class altogether.
// MyViewController.h
#import <UIKit/UIKit.h>
#implementation MyViewController : UIViewController
#end
// MyViewController.m
#implementation MyViewController
- (void)viewDidLoad {
[super viewDidLoad];
UISwipeGestureRecognizer *oneFingerSwipeRight =
[[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(oneFingerSwipeRight:)];
[oneFingerSwipeRight setDirection:UISwipeGestureRecognizerDirectionRight];
[self.view addGestureRecognizer:oneFingerSwipeRight];
UISwipeGestureRecognizer *oneFingerSwipeLeft =
[[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(oneFingerSwipeLeft:)];
[oneFingerSwipeLeft setDirection:UISwipeGestureRecognizerDirectionLeft];
[self.view addGestureRecognizer:oneFingerSwipeLeft];
UISwipeGestureRecognizer *twoFingerSwipeRight =
[[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(twoFingerSwiperight:)];
[twoFingerSwipeRight setDirection:UISwipeGestureRecognizerDirectionRight];
twoFingerSwipeRight.numberOfTouchesRequired = 2;
[self.view addGestureRecognizer:twoFingerSwipeRight];
UISwipeGestureRecognizer *twoFingerSwipeLeft =
[[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(twoFingerSwipeLeft:)];
[twoFingerSwipeLeft setDirection:UISwipeGestureRecognizerDirectionLeft];
twoFingerSwipeLeft.numberOfTouchesRequired = 2;
[self.view addGestureRecognizer:twoFingerSwipeLeft];
}
- (void)oneFingerSwipeRight:(UISwipeGestureRecognizer *)recognizer {
// Your code here
}
- (void)oneFingerSwipeLeft:(UISwipeGestureRecognizer *)recognizer {
// Your code here
}
- (void)twoFingerSwiperight:(UISwipeGestureRecognizer *)recognizer {
// Your code here
}
- (void)twoFingerSwipeLeft:(UISwipeGestureRecognizer *)recognizer {
// Your code here
}
#end
Also, one side note. It's recommended that you start class names with a capital letter, and start variable and functions with a lowercase letter. It helps make your code much more readable.

initWithFrame is filling the screen instead of creating a frame of the size I want

I'm new to Cocoa development and suspect that this is a noob issue.
I'm creating a simple background canvas with a bespoke UIView. I was expecting that I would be able to create this canvas to be slightly indented down from the main view so that I could add a toolbar at a later date. However, when I use initWithFrame (and any other init for that matter), the canvas is always created to be the size of the full screen rather than slightly smaller than the full screen. Even if I completely override the values for CGRect it doesn't make a difference. I've set a touchesBegan event and set the background colour to green to be able to determine success but all I get are a completely green screen and a touch event that works everywhere.
Please help - this is driving me mad and I can't find the answer anywhere on the web.
The relevant code is as follows (there actually isn't much more code than this in the whole app so far):
AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.objMainViewController = [[MainViewController alloc] init];
self.window.rootViewController = self.objMainViewController;
[self.window makeKeyAndVisible];
return YES;
}
MainViewController.h
#import <UIKit/UIKit.h>
#import "viewCanvas.h"
#interface MainViewController : UIViewController
#property (strong, nonatomic) viewCanvas *objViewCanvas;
-(id)init;
#end
MainViewController.m
#import "MainViewController.h"
#import "viewCanvas.h"
#implementation MainViewController
#synthesize objViewCanvas;
-(id)init
{
if (self = [super init]) {
CGRect frame = CGRectMake(100, 100, 100, 100);
objViewCanvas = [[viewCanvas alloc] initWithFrame:frame];
}
return self;
}
- (void)loadView {
self.view = objViewCanvas;
}
- (void)viewDidLoad
{
[super viewDidLoad];
}
viewCanvas.h
#import <UIKit/UIKit.h>
#import "viewCanvas.h"
#interface viewCanvas : UIView {
}
//Init
- (id) initWithFrame:(CGRect)frame;
//Events
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event;
#end
viewCanvas.m
#import "viewCanvas.h"
#implementation viewCanvas
//Standard inits
- (id) initWithFrame:(CGRect)frame{
self = [super initWithFrame:frame];
[self setBackgroundColor:[UIColor greenColor]];
return self;
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Touches Began Canvas" message:#"Canvas Touches Began" delegate:self cancelButtonTitle:#"Cancel" otherButtonTitles: nil];
[alert show];
}
#end
I think by default the view of a view controller fills the whole screen, so you need to add a subview to that view that's your smaller viewCanvas object (BTW, you should conform to the naming rules and name your classes with capital letters, ViewCanvas). Try this in your MainViewController .m file:
-(id)init{
if (self = [super init]) {
CGRect frame = CGRectMake(100, 100, 100, 100);
objViewCanvas = [[ViewCanvas alloc] initWithFrame:frame];
self.contentView = [[UIView alloc] initWithFrame:CGRectMake(1, 1, 1, 1)]; //this frame doesn't matter
[self.contentView setBackgroundColor:[UIColor whiteColor]];
}
return self;
}
- (void)loadView {
self.view = self.contentView;
[self.view addSubview:objViewCanvas];
}