Collectives™ on Stack Overflow
Find centralized, trusted content and collaborate around the technologies you use most.
Learn more about Collectives
Teams
Q&A for work
Connect and share knowledge within a single location that is structured and easy to search.
Learn more about Teams
Ask Question
I’m trying to make a
delegate
that will send messages from
UIButtons
within a custom
UIView
called
SGView
and am a bit out of my depth following the error messages. I recently learned how to get a
delegate to send messages successfully from within an instance method
.
SGView
includes a class method that arranges multiple
UIButtons
in a circle and was designed to be used by different
UIViews.
The geometry works when the method is called from a parent UIView
. I have now declared the
delegate
by adding
@protocol
and
@property
to the class method declaration
like so ...
SGView.h
#import <UIKit/UIKit.h>
@protocol SGViewDelegate <NSObject>
-(void)buttonPressed:(UIButton*)button;
@interface SGView : UIView {
+(id)circleOfButtons:(int)buttonCount buttonSize:(CGFloat)buttonSize circleRadius:(CGFloat)circleRadius;
@property (assign) id<SGViewDelegate> delegate;
SGView.m is essentially like this
#import "SGView.h"
@implementation SGView : UIView
+(id)circleOfButtons:(int)buttonCount buttonSize:(CGFloat)buttonSize circleRadius:(CGFloat)circleRadius
UIView *multipleViews = [self new];
// … circular geometry …
[circleButton addTarget:self action:@selector(buttonPressed:) forControlEvents:UIControlEventTouchUpInside];
[multipleViews addSubview:circleButton];
return multipleViews;
The moment I change the target from self to self.delegate in the target action statement above, Xcode reports three errors
Definition of 'objc_class' must be imported from module
'ObjectiveC.runtime' before it is required
No member named 'delegate' in 'struct objc_class'
Member reference type 'struct objc_class *' is a pointer; did you mean
to use '->'?
Xcode offers a Fixit for the last of these
Fixit Replace”.” with “->”
By accepting the Fixit I removed the three issues and introduced another
Member reference base type 'Class' is not a structure or union
If this Fixit has lead me in the right direction, what exactly should I be doing next ?
I need to ask this question to make sense of what might seem a straight forward problem before diving back into the Apple documentation and these tutorials trying to solve it. Any help is most appreciated. Thanks.
SOLUTION
This can be found in my answer to my own question.
Changing the class method to an instance method appears to have solved my problem.
This involved making the class method +(id)circleOfButtons:... etc into an instance method (-(id)circleOfButtons:... etc) in both .m and .h files. It was also necessary to change the call in the parent UIView from
SGView *sgView = [SGView circleOfButtons:count buttonSize:size circleRadius:radius];
SGView *sgView = [[SGView alloc] circleOfButtons:count buttonSize:size circleRadius:radius];
and change the declaration in SGView from
UIView *multipleViews = [self new];
UIView *multipleViews = [[UIView alloc]initWithFrame:[UIScreen mainScreen].bounds];
SGView can be now reused from different UIViews that change the number and size of UIButtons arranged in a circle. The delegate in SGView also allows each button to send a tagged message to a method in another class - in my case the ViewController.
The complete listing is included below and I'd welcome suggestions or improvements from others with more experience in OO programming.
ViewController.h
#import <UIKit/UIKit.h>
@interface ViewController : UIViewController <UIContentContainer> {
ViewController.m
#import "ViewController.h"
#import "FamilyView.h"
@interface ViewController ()
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
NSLog(@"load FamilyView");
CGRect rect = [UIScreen mainScreen].bounds;
float statusBarHeight = [[UIApplication sharedApplication] statusBarFrame].size.height;
CGRect screenFrame = CGRectMake(0, statusBarHeight, rect.size.width, rect.size.height - statusBarHeight);
self.view = [[UIView alloc] initWithFrame: screenFrame];
FamilyView *cv = [[FamilyView alloc]initWithFrame:screenFrame];
[self.view addSubview:cv];
- (void)buttonPressed:(UIButton*)button {
NSLog(@"Button %ld clicked.", (long int)[button tag]);
switch (button.tag) {
case 1:
// [self goToFamily1];
break;
case 2:
// [self goToFamily2];
break;
case 3:
// [self goToFamily3];
break;
case 4:
// [self goToFamily4];
break;
case 5:
// [self goToFamily5];
break;
default:
// [self goToHelp];
break;
FamilyView.h
#import <UIKit/UIKit.h>
#import "ViewController.h"
#import "SGView.h"
@interface FamilyView : UIView {
FamilyView.m
#import <UIKit/UIKit.h>
#import "FamilyView.h"
#import "SGView.h"
@implementation FamilyView : UIView
- (id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:[UIScreen mainScreen].bounds];
if (self) {
self.backgroundColor = [UIColor lightGrayColor];
int count = 5; //16;
CGFloat size = 80; //41;
CGFloat radius = 68; //105;
SGView *sgView = [[SGView alloc] circleOfButtons:count buttonSize:size circleRadius:radius];
[self addSubview:sgView];
return self;
SGView.h
#import <UIKit/UIKit.h>
@protocol SGViewDelegate <NSObject>
-(void)buttonPressed:(UIButton*)button;
@interface SGView : UIView {
-(id)circleOfButtons:(int)buttonCount buttonSize:(CGFloat)buttonSize circleRadius:(CGFloat)circleRadius;
@property (assign) id<SGViewDelegate> delegate;
SGView.m
#import "SGView.h"
@implementation SGView : UIView
-(id)circleOfButtons:(int)buttonCount buttonSize:(CGFloat)buttonSize circleRadius:(CGFloat)circleRadius
UIView *multipleViews = [[UIView alloc]initWithFrame:[UIScreen mainScreen].bounds];
CGPoint screenCentre;
CGPoint buttonCentre;
screenCentre.x = CGRectGetWidth ([UIScreen mainScreen].bounds) / 2;
screenCentre.y = CGRectGetHeight ([UIScreen mainScreen].bounds) / 2;
for (int i = 1; i <= buttonCount; i++) {
CGFloat radians = 2 * M_PI * i / buttonCount;
CGFloat arcStartPoint = - M_PI / 2; // first point clockwise after 12 o'clock
buttonCentre.x = screenCentre.x + circleRadius * cos(radians + arcStartPoint);
buttonCentre.y = screenCentre.y + circleRadius * sin(radians + arcStartPoint);
CGPoint target = CGPointMake(buttonCentre.x, buttonCentre.y);
CGFloat x = screenCentre.x - buttonSize / 2;
CGFloat y = screenCentre.y - buttonSize / 2;
CGFloat wide = buttonSize;
CGFloat high = buttonSize;
UIButton *circleButton = [[UIButton alloc] initWithFrame:CGRectMake(x, y, wide, high)];
[circleButton setTag:i];
[circleButton addTarget:self.delegate action:@selector(buttonPressed:) forControlEvents:UIControlEventTouchUpInside];
circleButton.clipsToBounds = YES;
circleButton.layer.masksToBounds = NO;
circleButton.layer.shadowOffset = CGSizeMake(-15, 20);
circleButton.layer.shadowRadius = 5;
circleButton.layer.shadowOpacity = 0.0;
circleButton.layer.borderWidth = 0.25f;
circleButton.layer.cornerRadius = buttonSize/2;
circleButton.layer.borderColor = [UIColor blackColor].CGColor;
circleButton.backgroundColor = UIColor.whiteColor;
[circleButton setTitle:[NSString stringWithFormat:@"%i", i] forState:UIControlStateNormal];
if (buttonCount > 25) {
[circleButton setTitleColor: [UIColor clearColor] forState:UIControlStateNormal];
} else {
[circleButton setTitleColor: [UIColor grayColor] forState:UIControlStateNormal];
[multipleViews addSubview:circleButton];
// animation 1
[UIView animateWithDuration:0.5 animations:^{
circleButton.transform = CGAffineTransformMakeScale(1.0, 1.0);
circleButton.center = screenCentre;
completion:^(BOOL finished){}];
// animation 2
[UIView animateWithDuration:0.5f animations:^{
circleButton.transform = CGAffineTransformIdentity;
circleButton.center = target;
completion:^(BOOL finished){}];
return multipleViews;
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.