I'm new to objective-c and iOS programming.I want to use a custom number pad for a game input. There are several types of games, (game1 game2 game3) and the games may require more or less numbers to be displayed on the number pad (control).
Each games rules and display properties are written in separate view controller classes. I tried cutting and pasting a copy of the number pad from game1 to the other controllers. It throws an error (at build), saying the name for the number buttons properties that I am using have already been used.
Will this would require me to rename and relink all object and properties for each game. To much maintenance overhead for me. So I have been trying to make a NumPad class, derived from NSObject.
This works fine until I try to create a view/container view from the non view controller class. I instantiate the numpad object in the viewdidload section of the game1 view controller. This is what I have so far.
.h file
#import <Foundation/Foundation.h>
#import "NumberPadTestAppDelegate.h"
#interface NumPad : NSObject
-(void)numberPadSetUp: (int) numberOfButtons;
#end
.m file
#import "NumPad.h"
#implementation NumPad
-(void)numberPadSetUp: (int) numberOfButtons
{
// Instantiate a Container View by code??? test.
CGRect frame = CGRectMake(14, 47, 740, 370);
UIView *Mycontainer = [[UIView alloc] initWithFrame:frame];
Mycontainer.backgroundColor = [UIColor blueColor];
[Mycontainer addSubview:Mycontainer];
// This was here for testing before adding the above four lines.
for (int a = 1; a < numberOfButtons +1; a++)
{
NSLog(#"Button %i has been added.",a);
}
NSLog(#" ");
NSLog(#"Numberpad setup is complete.");
} // End of "numberPadSetUp" routine.
#end
.m file from game1 test controller
#import "NumberPadTestViewController.h"
#interface NumberPadTestViewController ()
#end
#implementation NumberPadTestViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
NumPad *MyNumberPad =[[NumPad alloc]init];
[MyNumberPad numberPadSetUp:9];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
This code gives a run time error as written.
int main(int argc, char * argv[])
{
#autoreleasepool {
return UIApplicationMain(argc, argv, nil, NSStringFromClass([NumberPadTestAppDelegate class]));
}
}
I was also wondering if using the container view control in IB would accomplish the task or might I get the same naming errors as before?
What am i missing here?
Problem is in this line
[Mycontainer addSubview:Mycontainer];
You are declaring Mycontainer and adding it to itself. You should write class like follow
#import "NumPad.h"
#implementation NumPad
#define kButtonWidth 50
#define kButtonHeight 15
#define kPadding 20
-(void)numberPadSetUp: (int) numberOfButtons
{
// Instantiate a Container View by code??? test.
// This was here for testing before adding the above four lines.
int xPos = 0;
int yPos = 0;
for (int a = 1; a < numberOfButtons +1; a++)
{
UIButton *aButton = [UIButton buttonWithType:UIButtonTypeSystem];
CGRect aButtonFrame = CGRectMake(xPos, yPos, kButtonWidth, kButtonHeight);
aButton.frame = aButtonFrame;
[aButton setTitle:[NSString stringWithFormat:#"%d",a] forState:UIControlStateNormal];
[self addSubview:aButton];
xPos+=kButtonWidth+kPadding;
if(fmod(a, 3)==0){
yPos+=kButtonHeight+kPadding;
xPos = 0;
}
NSLog(#"Button %i has been added.",a);
}
NSLog(#" ");
NSLog(#"Numberpad setup is complete.");
} // End of "numberPadSetUp" routine.
#end
And in your main class
NumPad *MyNumberPad =[[NumPad alloc]initWithFrame:CGRectMake(14, 47, 740, 370)];
[MyNumberPad numberPadSetUp:9];
[self.view addSubview:MyNumberPad];
[self.view bringSubviewToFront:MyNumberPad];
This will give you result like following images in iOS6/iOS7
Related
If I define a constant as an integer, how is it recognised as a float ?
I built and ran the code below without problems under Xcode 6.1.1. The problem only appeared after I upgraded to Xcode 7.2 (7C68) and El Capitan.
iOSCircleView.m
int const SECTORS_80 = 80;
#implementation iOSCircleView
- (void)ViewSettings_OverView {
sectors = SECTORS_80;
NSLog(#"sectors %i", sectors);
}
When I run it NSLog reports a warning
Format specifies type ‘int’ but the argument has type ‘float’
The console displays
2016-01-07 10:05:00.210 AutoDrawUI[1298:555384] sectors 855670784
If I change NSLog command to
NSLog(#"sectors %f”, sectors);
and rerun the code, there is no warning but the console displays
2016-01-07 10:38:01.547 AutoDrawUI[1330:632806] sectors 80.000000
This seems like a bug. But maybe I’ve missed something
Here is the Original Code
int const SECTORS_80 = 80;
#implementation iOSCircleView
// Initialisation
// frame a view for drawing
- (id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
// Initialization code
totalCircles = [[NSMutableArray alloc] init];
centre = [[NSMutableArray alloc] init];
ring = [[NSMutableArray alloc] init];
// Set background color
self.backgroundColor = [UIColor grayColor];
}
return self;
}
// initialise single target view (7 others are commented out)
- (void)drawRect:(CGRect)rect {
[self ViewSettings_OverView]; // 1. "launch view" ??
}
Running (note: the problem occurs before it gets here)
// run
- (void)autoDrawUI {
[self drawCircle];
}
Here is the full class (unedited)
// initialise display settings
- (void)ViewSettings_OverView {
viewState = 0;
// number of dots on perimeter
sectors = SECTORS_80; // WARNING HERE
limit = sectors;;
if (sectors <= 0) { // WARNING HERE
show = FALSE; // disable
} else
show = TRUE; // enable perimeter dots
// radius of large circle perimeter
uberRadius = UBERRADIUS_52;
// radius of dots on large circle perimeter
dotRadius = DOTRADIUS_4;
dotsFilled = TRUE; // outline
oneColour = TRUE; // every colour
alternateDots = TRUE; // alternately filled and coloured
oddEvenState = 1; // PlayView
ringDot = RINGDOT_HIDE; //_SHOW104
centreDotFilled = FALSE; // fill or outline
centreDot = CENTREDOT_HIDE; //CENTREDOT_SHOW26;
centreDotFilled = TRUE; // fill or outline
NSLog(#"View %i", viewState);
NSLog(#"sectors %i", sectors); // WARNING HERE
NSLog(#"show %i", show);
[self centreReference];
}
And here is the .h file
#import <UIKit/UIKit.h>
#interface iOSCircleView : UIView
{
NSMutableArray *totalCircles;
NSMutableArray *sectorDots;
// following Stackoverflow 08/02/2015 ?
NSMutableArray *centre; // 1 of 5 (Global View), centre (Wait View), even bell icon (Play View)
NSMutableArray *ring; // odd bell icon (Play View)
// TO DO
NSMutableArray *sectorDotsCyan; // 16 moons surround 1 of 5 buttons on Global View
NSMutableArray *sectorDotsRed; // 16 moons 2
NSMutableArray *sectorDotsYellow; // 16 moons 3
NSMutableArray *sectorDotsMagenta; // 16 moons 4
NSMutableArray *sectorDotsGreen; // 16 moons 5
int dotCount, // working
colourIndex, // working
toggleIndex, // working
imageIndex,
limit, // working
selectedZone, // working
selectedPhone,
selectedState,
state,
viewState, // working
ringDotFilled,
centreDotFilled, // working
dotsFilled, // working
labelShown,
oneColour, // working
alternateDots,
i, // working
show; // working
BOOL shakeTap, // PlayView
oddEvenPhone, // LocalView
oddEvenState; // working
float uberX, // working
uberY, // working
uberRadius, // working
uberAngle, // working
labelX,
labelY,
dotRadius, // working
sectors, // working
x, // working
y, // working
ringDot, // working
centreDot, // working
textOffset, // working
startAngle,
dotAngle,
endAngle,
angle;
CGPoint dotPosition;
CGRect boxBoundary;
CGContextRef context;
}
#property(nonatomic,retain) UIColor* fillColor;
#property(nonatomic,retain) UIColor* circle;
#property(nonatomic,retain) UIImage* anImage;
- (void)drawCircle;
- (void)drawRosette;
#end
... and the problem becomes immediately obvious. I declared sectors as float and somehow how I got away with this previously. My brain's still on holiday!
Your issue has nothing to do with SECTORS_80. It's all about the sectors variable since that is the variable you are logging. You didn't specify how it is declared but clearly the error indicates that you declared it as a float.
Change:
float sectors;
to:
int sectors;
Or change the format to use %f. Either way will remove the error. But only one is really appropriate depending on your needs.
I have this typedef in my .h file
typedef struct
{
NSInteger openTime;
NSInteger closeTime;
} ShopHours;
Now I want to declare it in my .m file and then like you would a NSString that you want to use throughout the .m.
SO basically I want to initialize it, as an array of the typedef and then so I can assign it a vaule in my viewDidLoad method, as I see fit.
So basically I want to declare it like
ShopHours weekSchedule[] = {};
And then in viewDidLoad
weekSchedule[] = {//my data}
But when I try to declare and use it like this I get compile error
Field has incomplete type 'SHopHours[]'
Thanks for the help in advance
The compiler needs to know how big the weekSchedule variable is in order to put some memory aside for it. You could declare it as shopHours weekSchedule[7] for example.
I tried, the problem was you need to decleare the size of the array first :
#interface LoginScreen (){
ShopHours aa[5];
}
- (void)viewDidLoad
{
[super viewDidLoad];
for (int i = 0; i < 5; i++) {
aa[i].closeTime = 5+i;
aa[i].openTime = 10 + i;
}
}
In another method I logged it:
for (int i = 0; i < 5; i++) {
NSLog(#"Open Time %ld\n",(long)aa[i].openTime);
NSLog(#"Close Time %ld\n",(long)aa[i].closeTime);
}
Works just fine.
If you want dynamic memory allocation,you can do it
#interface LoginScreen (){
ShopHours *aa;
}
- (void)viewDidLoad
{
[super viewDidLoad];
aa = malloc(sizeof(ShopHours) * 5);
for (int i = 0; i < 5; i++) {
aa[i].closeTime = 5+i;
aa[i].openTime = 10 + i;
}
}
Hope this helops.. :)
I'm using google maps SDK 1.7.2 on a projectd using iOS 7 (I just upgraded it from iOS6). For some reason all the GMSMapViewDelegate callbacks work but this one
- (BOOL) didTapMyLocationButtonForMapView: (GMSMapView *)mapView
I'm assuming this should be called when the arrow button is tapped right? Any idea why it isn't?
This is how I instantiate the mapsview:
mapView_ = [GMSMapView mapWithFrame:[[self mainView] bounds]
camera:[self currentCameraUseStandartZoom:YES]];
[[mapView_ settings] setMyLocationButton:YES];
[mapView_ setDelegate:self];
[[self mainView] addSubview:mapView_];
I use a pretty reliable method to find the my location button.
Initially when a map view is created the button is hidden. And I go through map view hierarchy to find all hidden buttons. Then I set self.mapView.settings.myLocationButton = YES and check if any of the buttons I found is not hidden anymore.
Here is the code I use:
- (UIButton*)findAndShowMyLocationButton
{
NSMutableArray* hiddenButtons = [NSMutableArray array];
[self findHiddenButtonsInView:self.mapView hiddenButtons:hiddenButtons];
self.mapView.settings.myLocationButton = YES;
for (UIButton* button in hiddenButtons) {
if (!button.hidden) return button;
}
return nil;
}
- (void)findHiddenButtonsInView:(UIView*)view hiddenButtons:(NSMutableArray*)hiddenButtons
{
for (UIView* subview in view.subviews) {
if (subview.hidden && [subview isKindOfClass:[UIButton class]]) {
[hiddenButtons addObject:subview];
} else {
[self findHiddenButtonsInView:subview hiddenButtons:hiddenButtons];
}
}
}
And finally
- (void)viewDidLoad
{
...
UIButton* myLocationButton = [self findAndShowMyLocationButton];
[myLocationButton addTarget:self action:#selector(myLocationClick) forControlEvents:UIControlEventTouchUpInside];
}
just in case someone is having the same problem.. i pretty much resolved this by using a hack.. here it is:
in my main.m file I customized the UIResponder class:
int main(int argc, char *argv[])
{
#autoreleasepool {
return UIApplicationMain(argc, argv, NSStringFromClass([TPMUApplication class]), NSStringFromClass([TPMUAppDelegate class]));
}
}
TPMUApplication.h
#import <UIKit/UIKit.h>
#class TPMUTaxiRequestVC;
#interface TPMUApplication : UIApplication
// basically the view controller that will be informed that
// the user has tapped the my location button, normally it would subscribe to
// the GMSMapViewDelegate protocol, and it should have a GMSMapView property
#property (nonatomic, strong) TPMUTaxiRequestVC *taxiRequestVC;
#end
TPMUApplication.m
#import "TPMUApplication.h"
#import "TPMUTaxiRequestVC.h"
#implementation TPMUApplication
- (void)sendEvent:(UIEvent *)event
{
[super sendEvent:event];
UIView *touchReceipientView =((UITouch *)[event.allTouches anyObject]).view;
NSLog(#"");
CGRect myLocationButtonFourchIncFrame = CGRectMake(256, 525, 64, 54);
CGRect myLocationButtonThreeHalfIncFrame = CGRectMake(256, 336, 64, 54);
if (CGRectEqualToRect(touchReceipientView.frame, myLocationButtonFourchIncFrame) ||
CGRectEqualToRect(touchReceipientView.frame, myLocationButtonThreeHalfIncFrame)) {
if (self.taxiRequestVC.mapState != TPMUMapStateInMotionAsResultOfMyLocationButtonTap) {
self.taxiRequestVC.mapState = TPMUMapStateInMotionAsResultOfMyLocationButtonTap;
// notice that didTapMyLocationButtonForMapView is actually
// a method in the GMSMapViewDelegate protocol.. and since
// taxiRequestVC subscribes to that protocol.. we simply call it here
// as if it was natively called
[self.taxiRequestVC didTapMyLocationButtonForMapView:self.taxiRequestVC.mapView];
}
}
}
#end
and just in case you were wondering, TPMUMapStateInMotionAsResultOfMyLocationButtonTap is a state of a state machine variable with the following states:
typedef enum
{
TPMUMapStateIdle = 0,
TPMUMapStateInMotionAsResultOfUserGesture,
TPMUMapStateInMotionAsResultOfMyLocationButtonTap
} TPMUMapState;
since I wanted to track motion in the map as a result of location button tap vs user gesture.
hope this helps!
I am experiencing a rather serious issue with my iPhone app using ARC.
I have a viewcontroller (lets call this A). This viewcontroller opens a navigationcontroller as a modal which runs through 3 different viewcontrollers (lets call these 1, 2 and 3). After viewing number 3 the navigationcontroller closes and we're back to A again.
So the flow is: A opens navigationcontroller and goes through 1->2->3 and then it closes again.
Every time I go through this flow i lose memory. I've searched through all my files looking for any retain og strong properties, un-invalidated timers or similar in order to solve this problem.
I have one idea, which might be the problem. At viewcontroller 1 i present a animation using coreanimation and a sprite. I'm using a implementation made by someone else. It seems like if i disable the animations the memory used seems quite constant (and thereby no memory loss). I have modified the implementation a bit to use ARC. This is the implementation I use for my sprite animations:
MCSpriteLayer.h
//
// MCSpriteLayer.h
//
// Created by Miguel Angel Friginal on 8/20/10.
// Copyright 2010 Mystery Coconut Games. All rights reserved.
//
#import <Foundation/Foundation.h>
#import <QuartzCore/QuartzCore.h>
#interface MCSpriteLayer : CALayer {
unsigned int sampleIndex;
}
// SampleIndex needs to be > 0
#property (nonatomic) unsigned int sampleIndex;
// For use with sample rects set by the delegate
+ (id)layerWithImage:(CGImageRef)img;
- (id)initWithImage:(CGImageRef)img;
// If all samples are the same size
+ (id)layerWithImage:(CGImageRef)img sampleSize:(CGSize)size :(int)useRetina;
- (id)initWithImage:(CGImageRef)img sampleSize:(CGSize)size;
// Use this method instead of sprite.sampleIndex to obtain the index currently displayed on screen
- (unsigned int)currentSampleIndex;
#end
MCSpriteLayer.m
//
// MCSpriteLayer.m
//
// Created by Miguel Angel Friginal on 8/20/10.
// Copyright 2010 Mystery Coconut Games. All rights reserved.
//
#import "MCSpriteLayer.h"
#implementation MCSpriteLayer
#synthesize sampleIndex;
#pragma mark -
#pragma mark Initialization, variable sample size
- (id)initWithImage:(CGImageRef)img;
{
self = [super init];
if (self != nil)
{
self.contents = (__bridge id)img;
sampleIndex = 1;
}
return self;
}
+ (id)layerWithImage:(CGImageRef)img;
{
MCSpriteLayer *layer = [(MCSpriteLayer*)[self alloc] initWithImage:img];
return layer;
}
#pragma mark -
#pragma mark Initialization, fixed sample size
- (id)initWithImage:(CGImageRef)img sampleSize:(CGSize)size;
{
self = [self initWithImage:img];
if (self != nil)
{
CGSize sampleSizeNormalized = CGSizeMake(size.width/CGImageGetWidth(img), size.height/CGImageGetHeight(img));
self.bounds = CGRectMake( 0, 0, size.width, size.height );
self.contentsRect = CGRectMake( 0, 0, sampleSizeNormalized.width, sampleSizeNormalized.height );
}
return self;
}
+ (id)layerWithImage:(CGImageRef)img sampleSize:(CGSize)size :(int)useRetina;
{
CGSize newSampleSize;
if(useRetina == 1) {
// Supporting retina displays
if ([[UIScreen mainScreen] respondsToSelector:#selector(displayLinkWithTarget:selector:)] &&
([UIScreen mainScreen].scale == 2.0)) {
newSampleSize = CGSizeMake(size.width*2, size.height*2);
} else {
newSampleSize = size;
}
} else
newSampleSize = size;
MCSpriteLayer *layer = [[self alloc] initWithImage:img sampleSize:newSampleSize];
return layer;
}
#pragma mark -
#pragma mark Frame by frame animation
+ (BOOL)needsDisplayForKey:(NSString *)key;
{
return [key isEqualToString:#"sampleIndex"];
}
// contentsRect or bounds changes are not animated
+ (id < CAAction >)defaultActionForKey:(NSString *)aKey;
{
if ([aKey isEqualToString:#"contentsRect"] || [aKey isEqualToString:#"bounds"])
return (id < CAAction >)[NSNull null];
return [super defaultActionForKey:aKey];
}
- (unsigned int)currentSampleIndex;
{
return ((MCSpriteLayer*)[self presentationLayer]).sampleIndex;
}
// Implement displayLayer: on the delegate to override how sample rectangles are calculated; remember to use currentSampleIndex, ignore sampleIndex == 0, and set the layer's bounds
- (void)display;
{
if ([self.delegate respondsToSelector:#selector(displayLayer:)])
{
[self.delegate displayLayer:self];
return;
}
unsigned int currentSampleIndex = [self currentSampleIndex];
if (!currentSampleIndex)
return;
CGSize sampleSize = self.contentsRect.size;
self.contentsRect = CGRectMake(
((currentSampleIndex - 1) % (int)(1/sampleSize.width)) * sampleSize.width,
((currentSampleIndex - 1) / (int)(1/sampleSize.width)) * sampleSize.height,
sampleSize.width, sampleSize.height
);
}
#end
Is this implementation somehow not realeasing correctly or retaining anything? Thanks in advance.
Update
- I am using Instruments to measure the memory. I am using the Memory Monitor where I keep an eye on the Physical Memory Free
- The image is created like this:
NSString *path = [[NSBundle mainBundle] pathForResource:#"round_start.png" ofType:nil];
CGSize fixedSize = CGSizeMake(320, 480);
mascot = [MCSpriteLayer layerWithImage:[UIImage imageWithContentsOfFile:path].CGImage sampleSize:fixedSize :0];
mascot.frame = CGRectMake(ANIMATION_X, ANIMATION_Y, ANIMATION_WIDTH, ANIMATION_HEIGHT);
[self.view.layer addSublayer:mascot2];
CABasicAnimation *anim = [CABasicAnimation animationWithKeyPath:#"sampleIndex"];
anim.delegate = self;
anim.fromValue = [NSNumber numberWithInt:1];
anim.toValue = [NSNumber numberWithInt:52];
anim.duration = ANIMATION_DURATION;
anim.repeatCount = 1;
[mascot addAnimation:anim forKey:nil];
- I've been experiencing with closing the modal with
[self dismissModalViewControllerAnimated:YES];
and
[self.navigationController dismissModalViewControllerAnimated:YES];
Dismissing the navigation controller does not release it, assuming you have a strong reference to it (that would need to get nil'd). In the view controllers used by it, add a log message in the dealloc method, so you know they are getting dealloced (you can do this for any subclassed item). If needed you can create a simple UINavigation subclass for the sole purpose of adding a message in dealloc). You will find that one or more of these items are not getting dealloced, and then you need to figure out if they are retained by a property/ivar or because they still have a superview.
I tried to use Cleaver, that is PhoneGap / Cordova as a component of an existing iOS application. I followed this step by step guide twice, without success.
My application can easily instantiate a web view, and i can pass content to it using the stringbyevaluatingjavascriptfromstring method, but as soon as i try to access PhoneGap API (navigator.compass, navigator.network, ...), nothing seems to work. console.log(navigator) shows no sign of Cordova objects (console.log does not output anything is Xcode, i'm using http://debug.phonegap.com/). The deviceready event is not triggered either.
In my html file, i include PhoneGap js file cordova-1.7.0rc1.js which i copied from another project (since /www folder is missing when you use PhoneGap as a component).
My ViewController.h imports <Cordova/CDVViewController.h>.
Here my ViewController.m
//
// ViewController.m
// CordovaComponent
//
#import "ViewController.h"
#interface ViewController (){
CDVViewController *cdvViewController ;
}
#end
#implementation ViewController
- (void)pushPhoneGap:(id)sender {
cdvViewController = [[CDVViewController alloc] init];
cdvViewController.wwwFolderName = #"www";
cdvViewController.startPage = #"index.html";
cdvViewController.view.frame = self.view.bounds;
cdvViewController.webView.delegate = self;
[self.navigationController pushViewController:cdvViewController animated:YES];
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
UIButton * button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[button setTitle:#"Push PhoneGap view" forState:UIControlStateNormal];
[button addTarget:self action:#selector(pushPhoneGap:) forControlEvents:UIControlEventTouchUpInside];
button.frame = CGRectMake(60, 50, 200., 50.);
[self.view addSubview:button];
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
}
- (void)webViewDidFinishLoad:(UIWebView *)webView {
NSString *jsReturn = [cdvViewController.webView stringByEvaluatingJavaScriptFromString:#"setArray([1, 1, 2, 3, 5, 8, 13, 21, 34, 1]);"];
NSLog(jsReturn);
}
#end
Do you have an idea of what's happening ? Any help would be greatly appreciated !
Okay, after many hours of trying to solve this issue, I finally found what was going wrong.
This is the line that messed things up:
cdvViewController.webView.delegate = self;
You can't just override the delegate of the view controllers's web view. The original delegate has instantiation code which enables PhoneGap to run. Don't override it and everything will be fine !
If you want to get notified about webview events without breaking Cordova you could try something like this:
#interface WrappingWebViewDelegate : NSObject <UIWebViewDelegate>
#property (nonatomic,retain) id<UIWebViewDelegate> wrappedDelegate;
#end
#implementation WrappingWebViewDelegate
- (void)webViewDidStartLoad:(UIWebView*)theWebView {
[self.wrappedDelegate webViewDidStartLoad: theWebView];
// your code
}
// implement all other delegate methods and forward them to the wrapped delegate
[...]
#end
Usage like this:
cdvViewController = [[CDVViewController alloc] init];
WrappingWebViewDelegate wrappingDelegate = [[WrappingWebViewDelegate alloc] init];
wrappingDelegate.wrappedDelegate = cdvViewController.webView.delegate;
cdvViewController.webView.delegate = wrappingDelegate;
I haven't tested this, so you should be careful.