touchesBegan ignored in subclass of uiresponder - objective-c

working on an ios app with objective c and using xcode. I have a class that inherits from another class that inherits from UIResponder and it contains a view. I have a touchesBegan within the sub class but the event only gets called when running the app in debug/dev mode. when i make a production/release build the touch event is not getting called.
// Basic viewcontroller protocol
#protocol SubViewController
- (void)viewDidAppear:(BOOL)animated;
- (void)viewDidDisappear:(BOOL)animated;
- (void)viewWillAppear:(BOOL)animated;
- (void)viewWillDisappear:(BOOL)animated;
- (void)viewDidLoad;
-(UIView *)view;
#end
#interface SubViewController : UIResponder<SubViewController> {
}
/////////////////////////////////////////////////////////////////////////////////
// A custom subview controller
//
#interface mySubViewController : SubViewController {
}
and within mysubviewcontroller class i have
- (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
//some code and magic
}
Now as i said running this in debug is fine but the touch event is ignored in release. any tips, ideas or questions to help clarify this for you please say. thanks in advance
edit: i seen this in the doc "If you override this method without calling super (a common use pattern), you must also override the other methods for handling touch events, if only as stub (empy) implementations." so i stubbed in all the other touch events but no change on release build

As you're not subclassing UIViewController (which does this automatically), you need to add your responder to the responder chain manually.
A UIViewController's position in the responder chain is between its view and the view's superview, so to get the same behavior, you need to override nextResponder in both your view and the controller that manages it. The view should return the controller and the controller should return the view's superview.

Related

How to detect the key press with keyDown on mac (objective-c)

I am writing a keyDown in viewcontroller.m but it does not work.
This is my code:
-(BOOL)acceptsFirstResponder{
return YES;
}
-(void)keyDown:(NSEvent *)event{
NSLog(#"%hu",event.keyCode);
}
You always receive keyDown & mouseDown events in NSView class not in NSViewController class.
Create a subclass of NSView class, say it TestView and change default class of embedded NSView of NSViewController in Storyboard/Xib to TestView.
Also, it is always recommended to forward events to superclass especially one which you don't want to handle.
-(void)keyDown:(NSEvent *)event
{
NSLog(#"%hu",event.keyCode);
[super keyDown:event];
}

Why is this delegate method automatically called in Objective-C?

I'm going through this book called "cocoa programming for mac os x" and I just started with delegates. This whole thing with delegates is still a little bit wacky to me but I think I just need to let it settle.
However there was this one exercise where I should implement a delegate of the main window so that if resized height is always 2xwidth.
So I got 4 files:
AppDelegate.h
AppDelegate.m
WindowDelegate.h
WindowDelegate.m
AppDelegate are just the two standard files that get created when you open a new Cocoa project. I had to look up the solution because I didn't quite know how to accomplish this task.
The solution was just to create a new cocoa class, "WindowDelegat.h/.m" and add this to it's implementation file:
- (NSSize)windowWillResize:(NSWindow *)sender toSize:(NSSize)frameSize {
NSSize newSize = frameSize;
newSize.height = newSize.width * 2;
return newSize;
}
Then I opened the interface builder, added a new object and made it my WindowDelegate. I then had to ctrl drag from the WindowDelegate to the actual window and made it the window's delegate.
Clicked run and it worked. Yay! But why?
First I thought that "windowWillResize" is just one of these callback functions that get's called as soon as the window is resized but it isn't. Normally methods get invoked because the general lifecycle of an program invokes them or because they are an #IBAction, a button or different control elements.
But "windowWillResize" is non of them. So why is it called?
EDIT: Problem solved! Thanks a lot!
Now I'm trying to connect the delegate to the window programmatically. Therefore I deleted the referencing outlet from WindowDelegate to the actual window in interface builder. It works but I just want to verify that this it the correct way how it's done:
AppDelegate.h
#import <Cocoa/Cocoa.h>
#import "WindowDelegate.h"
#interface AppDelegate : NSObject <NSApplicationDelegate>
#end
AppDelegate.m
#import "AppDelegate.h"
#interface AppDelegate ()
#property (weak) IBOutlet NSWindow *window;
#property (strong) WindowDelegate *winDeleg;
#end
#implementation AppDelegate
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
// Insert code here to initialize your application
}
- (void)applicationWillTerminate:(NSNotification *)aNotification {
// Insert code here to tear down your application
}
- (void)awakeFromNib {
[_window setOpaque:NO];
NSColor *transparentColor = [NSColor colorWithDeviceRed:0.0 green:0.0 blue:0.0 alpha:0.5];
[_window setBackgroundColor:transparentColor];
NSSize initialSize = NSMakeSize(100, 200);
[_window setContentSize:initialSize];
_winDeleg = [[WindowDelegate alloc] init];
[_window setDelegate: _winDeleg];
}
#end
WindowDelegate.h
#import <Foundation/Foundation.h>
#import <Cocoa/Cocoa.h>
#interface WindowDelegate : NSObject <NSWindowDelegate>
#end
WindowDelegate.m
#import "WindowDelegate.h"
#implementation WindowDelegate
- (NSSize)windowWillResize:(NSWindow *)sender toSize:(NSSize)frameSize {
NSSize newSize = frameSize;
newSize.height = newSize.width * 2;
return newSize;
}
- (id)init {
self = [super init];
return self;
}
#end
Why does the #property of WindowDelegate need to be strong?
And isn't my winDeleg an object? Why do I have to access it through _winDeleg when it's an object. I though the underscore is used to access variables?
Thank you for your help!
Clicked run and it worked. Yay! But why?
Because instances of NSWindow have a delegate property that can point to any object that implements the NSWindowDelegate protocol, and that protocol includes the -windowWillResize:toSize: method.
Read that a few times. The reason it's important is that you can create your own object, say that it implements NSWindowDelegate, implement -windowWillResize:toSize:, and set that object as your window's delegate. Then, whenever the user resizes the window, your method will be called and can modify the proposed new size.
Normally methods get invoked because the general lifecycle of an program invokes them or because they are an #IBAction, a button or different control elements. But "windowWillResize" is non of them. So why is it called?
This really isn't so different. Think of delegates as "helper objects." They let you customize the behavior of an object without having to create a whole new subclass. The NSWindowDelegate object is essentially a contract that the NSWindow promises to follow: whenever certain things happen, such as the user resizing the window, the window will call certain methods in its delegate object, if the delegate exists and implements those methods. In the case of NSApplication, a lot of those delegate methods are application lifecycle events, like the app starting up or quitting or getting a message from the operating system. In the case of NSWindow, delegate methods correspond to interesting events that can happen to a window, like the user moving it, hiding it, showing it, maximizing it, moving it to a different screen, etc. Other classes, like text views or network connections or movie players, have their own sets of interesting events and their own delegate protocols to match.
Note that methods marked IBAction really aren't delegate methods, they're just methods that get called by objects like controls that use a target/action paradigm. The IBAction keyword lets the IDE know which methods it should present as possible actions for things like buttons. You often find actions in window controllers and view controllers, and those objects frequently act as a delegate for some other object, but the actions themselves aren't part of the delegate protocol. For example, NSTableView takes a delegate object that determines how the table will act and what's displayed in it. It often makes sense for the view controller that manages the table to be the table's delegate, and that same view controller might also manage some buttons and contain the action methods that said buttons trigger, but the actions aren't part of the NSTableViewDelegate protocol and you therefore wouldn't call them delegate methods.

event touchesForView: returns null in super view

I have a subclass of UIView called BigView that overrides touchesMoved (among other things) like so:
#implementation BigView
- (void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
NSSet * viewTouches = [event touchesForView:self];
NSLog(#"set of touches: %#", viewTouches);
}
#end
My BigView instance also has a subview (regular UIView instance) - when I touch inside that subview, the above touchesMoved method gets called, but viewTouches comes up null. The subView doesn't override any of the event handling methods (touchesBegan, touchesMoved, etc). I would expect the touch count for a view to include all of the touches inside its subviews, but it doesn't seem to be working that way. Am I doing something wrong in the code, or is this the way it should work and I don't understand why? (If the latter, why is this better?)
Thank you!

PullToRefresh TableView inside UIViewController

I've got a UIViewController which is also the UITableViewDelegate, amongst other things, for a UITableView, created in FirstView.xib
#interface FirstViewController : UIViewController <
UITextFieldDelegate,
UITableViewDelegate,
UITableViewDataSource
> {
UITableView *searchResults; // this is the property for the table view
...
}
I want this table view to make use of PullToRefresh: https://github.com/leah/PullToRefresh, but the documentation there only explains how to make use of the class as a sub class of the view controller
#import "PullRefreshTableViewController.h"
#interface DemoTableViewController : PullRefreshTableViewController {
NSMutableArray *items;
}
My app uses a Tab bar as the root view controller, can anyone explain to me how I can make the UITableView into a PullRefreshTableView? When I don't have a UITableViewController to edit?
The secret is in the scroll view delegate methods which you can already respond to since you are acting as the tables delegate. This article provides a good start to create your own pull to refresh.
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
This will let you know when the user starts dragging the scrollview so you can begin checking whether to refresh or not.
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
This allows you to make necessary transitions while scrolling (mainly swapping text and flipping the arrow)
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView
willDecelerate:(BOOL)decelerate
This is where you decide if the user has dragged far enough down to start the refresh.
Use this API
It works fine with UIViewController

How do I handle a mousedown event inside a window in Cocoa

How do I handle a mousedown event inside a window in Cocoa?
My code:
-(void)mouseDown:(NSEvent *)event {
NSLog(#"yay");
}
I am using Mac OS10.6, in xcode 4.0.1.
EDIT:
Yes, this is in the app delegate, but this is my .h:
#interface jumperAppDelegate : NSWindow {
Which I have done before in app delegates (just not for mouse events). This is really annoying me
Make sure you inherit from NSWindow, as well as conform to the <NSWindowDelegate> protocol. Like this:
#interface YourWindow : NSWindow <NSWindowDelegate> {}
#end
Then you should receive the event notification.
-(void)mouseDown:(NSEvent *)event {
}
For this method to be called the class it is being called in needs to inherit from NSResponder. Windows and views are all subclasses of NSResponder. If the class you are calling this from is not a subclass of NSResponder then the method will not fire.
* Update *
Also be sure to override acceptsFirstResponder to return yes.
- (BOOL)acceptsFirstResponder {
return YES;
}
I don't know for sure, but I have heard that in your header file (.h) that you need to replace the "NSObject" with "NSWindow". I would test it but I am not at my computer right now.
Also, make sure that you put the following code into your header file:
- (void) mouseDown:(NSEvent*)event;
EDIT: I have done some tests and research, but I cannot get it to work. I have two tips though.
Use the '-acceptsFirstMouse method.
Try creating an NSEvent:
NSEvent * someEvent;
-(void)mouseDown:(NSEvent*)someEvent;
This probably won't work, but I will have more information tomarrow