I've Objective-C category for iOS 7.1 with property...here's header code
#import <UIKit/UIKit.h>
#interface UIViewController (CategoryName)
#property(nonatomic, copy) UITapGestureRecognizer *recognizer;
then I've .m file with code
#import "UIViewController+CategoryName.h"
#implementation UIViewController (CategoryName)
#dynamic recognizer;
...
- (void)myMethod {
// here it crashes!!!
self.recognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(anothermethod)];
...
}
...
#end
Importing category into viewcontroller and then calling [self myMethod] always crashes with message - unrecognized selector sent to instance pointing to line in myMethod where self.recognizer is initialized.
What am I doing wrong?
There's only 1 way to add properties to an objective-c category: that is by using associated objects.
Please use this guide to fix your code:
http://www.davidhamrick.com/2012/02/12/Adding-Properties-to-an-Objective-C-Category.html
Also, NSHipster did a blogpost on this subject and explains this matter really well:
http://nshipster.com/associated-objects/
To completely help you out of trouble, here's the code you should write to fix your problem:
#import <objc/runtime.h>
NSString * const recognizerPropertyKey = #"recognizerPropertyKey";
#implementation UIViewController (CategoryName)
#dynamic recognizer;
- (void)setRecognizer:(UITapGestureRecognizer *)recognizer {
objc_setAssociatedObject(self, (__bridge const void *)(recognizerPropertyKey), recognizer, OBJC_ASSOCIATION_COPY);
}
- (UITapGestureRecognizer *)recognizer {
return objc_getAssociatedObject(self, (__bridge const void *)(recognizerPropertyKey));
}
#end
Related
I'm using a swift pod in an objective C project.
I successfully access swift classes from objective-c, anyway I'm facing an issue to adopt swift protocol.
The compiler does not complain, generated bridging header seems correct.
Problem occurs at runtime when calling [self.sceneLocationView setLocationNodeTouchDelegate: self]; that results in [ARCL.SceneLocationView setLocationNodeTouchDelegate:]: unrecognized selector sent to instance.
I cannot find any solution to this issue, I spent time to search here, but still no luck to make this working.
Any help would be greatly appreciated.
Thanks
My swift and objective-c files are shown below.
SceneLocationView.swift:
#available(iOS 11.0, *)
open class SceneLocationView: ARSCNView {
...
#objc public weak var locationNodeTouchDelegate: LNTouchDelegate?
...
}
SceneLocationViewDelegate.swift :
#objc public protocol LNTouchDelegate: class {
func locationNodeTouched(node: AnnotationNode)
}
ViewController.h :
#import "ARCL-Swift.h"
#interface ViewController : UIViewController <LNTouchDelegate>{
}
#property (nonatomic, strong) SceneLocationView *sceneLocationView;
ViewController.m :
#import "ARCL-Swift.h"
#import "ViewController.h"
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.sceneLocationView = [[SceneLocationView alloc] init];
[self.sceneLocationView run];
[self.view addSubview: self.sceneLocationView];
...
[self.sceneLocationView setLocationNodeTouchDelegate: self]; <-- ERROR HERE
}
-(void) locationNodeTouchedWithNode:(AnnotationNode *)node {
}
ARCL-Swift.h :
SWIFT_PROTOCOL("_TtP4ARCL15LNTouchDelegate_")
#protocol LNTouchDelegate
- (void)locationNodeTouchedWithNode:(AnnotationNode * _Nonnull)node;
#end
SWIFT_CLASS("_TtC4ARCL17SceneLocationView") SWIFT_AVAILABILITY(ios,introduced=11.0)
#interface SceneLocationView : ARSCNView
#property (nonatomic, weak) id <LNTouchDelegate> _Nullable locationNodeTouchDelegate;
- (nonnull instancetype)init;
- (nonnull instancetype)initWithFrame:(CGRect)frame options:(NSDictionary<NSString *, id> * _Nullable)options OBJC_DESIGNATED_INITIALIZER;
- (nullable instancetype)initWithCoder:(NSCoder * _Nonnull)aDecoder OBJC_DESIGNATED_INITIALIZER;
- (void)layoutSubviews;
- (nonnull instancetype)initWithFrame:(CGRect)frame SWIFT_UNAVAILABLE;
#end
I need to pass a string from a NSObject class to a UIViewController, I understand that the best way is delegation but the delegate method isn't being called. I'm trying to set the UILabel an DieFacesViewController as the selectedOption from TemporarySelection.
A tableview shows the value of CustomOptionStore, once it's tapped passes its value to TemporarySelection and opens the modal view DieFacesViewCountroller which should, at least in my mind, take the label value from TemporarySelection. The reason I created TemporarySelection is because the DieFacesViewController will be used by other classes, not only by CustomOptionStore, and it will need to load the label from all those classes when different tableViews are selected.
I tried to set the delegate as self in both viewDidLoad and viewWillAppear with no luck, I don't understand if the view loads before being able to call the delegate method or if there's something wrong the way I set the method up.
I've been stuck here for two days, this is the first time I post a question so please forgive me if it's a bit confused.
my delegator class TemporarySelection.h is
#import <Foundation/Foundation.h>
#import "CustomOptionsStore.h"
#class DieFacesViewController;
#protocol TemporarySelectionDelegate <NSObject>
-(void)sendSelection;
#end
#interface TemporarySelection : NSObject
#property (nonatomic, weak) id <TemporarySelectionDelegate> delegate;
#property (nonatomic, strong) NSString *selectedOption;
-(void)addSelection: (CustomOptionsStore *) selection;
#end
and my TemporarySelection.m is
#import "TemporarySelection.h"
#implementation TemporarySelection
-(void)addSelection: (CustomOptionsStore *) selection{
self.selectedOption = selection.description;
[self.delegate sendSelection];
}
#end
the delegate class DiewFacesViewController.h is
#import <UIKit/UIKit.h>
#import "SelectedStore.h"
#import "TemporarySelection.h"
#interface DieFacesViewController : UIViewController <TemporarySelectionDelegate>
#property (strong, nonatomic) IBOutlet UILabel *SelectionName;
#end
and the DieFacesViewController.m is
#import "DieFacesViewController.h"
#interface DieFacesViewController ()
#end
#implementation DieFacesViewController
- (void)viewDidLoad {
TemporarySelection *ts = [[TemporarySelection alloc]init];
ts.delegate = self;
[super viewDidLoad];
}
-(void)sendSelection{
TemporarySelection *ts = [[TemporarySelection alloc]init];
self.SelectionName.text = ts.selectedOption;
}
-(void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:YES];
}
You are not setting the delegate object properly.Check the above code
#import "DieFacesViewController.h"
#interface DieFacesViewController ()<TemporarySelectionDelegate>
{
//global object
TemporarySelection *ts;
}
#end
#implementation DieFacesViewController
- (void)viewDidLoad {
ts = [[TemporarySelection alloc]init];
ts.delegate = self;
[super viewDidLoad];
}
-(void)sendSelection{
//Use the object to extract
self.SelectionName.text = ts.selectedOption;
}
-(void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:YES];
}
I have a protocol in one class:
#protocol DataStorageManager
- (void) saveFile;
#end
#interface DataManager : NSObject
{
id <DataStorageManager> delegate;
}
#property (nonatomic, assign) id<DataStorageManager> delegate;
//methods
#end
and its implementation:
#implementation DataManager
#synthesize delegate;
#end
and I have another class which is the adapter between the first and the third one:
#import "DataManager.h"
#import "DataPlistManager.h"
#interface DataAdapter : NSObject <DataStorageManager>
#property (nonatomic,strong) DataPlistManager *plistManager;
- (void) saveFile;
#end
and its implementation
#import "DataAdapter.h"
#implementation DataAdapter
-(id) initWithDataPlistManager:(DataPlistManager *) manager
{
self = [super init];
self.plistManager = manager;
return self;
}
- (void) saveFile
{
[self.plistManager savePlist];
}
#end
So when I in first method try to call my delegate method like this
[delegate saveFile];
Nothing happened. I don't understand what's wrong with the realization - it's a simple adapter pattern realization. So I need to use the delegate which will call the methods from the third class. Any help?
You are not setting the delegate property. You need to do this,
-(id) initWithDataPlistManager:(DataPlistManager *) manager
{
self = [super init];
self.plistManager = manager;
self.plistManager.delegate = self;
return self;
}
Also, in DataManager class remove the ivar declaration, just declaring property is sufficient, the ivar gets automatically created. Call the delegate method as below,
if([self.delegate respondsToSelector:#selector(saveFile)] {
[self.delegate saveFile];
}
Hope that helps!
In your case you forget to set your protocol delegate and also need to call protocol method
by self.delegate....
I just Give Basic Idea for how to Create Protocol
Also Read This Question
#DetailViewController.h
#import <UIKit/UIKit.h>
#protocol MasterDelegate <NSObject>
-(void) getButtonTitile:(NSString *)btnTitle;
#end
#interface DetailViewController : MasterViewController
#property (nonatomic, assign) id<MasterDelegate> customDelegate;
#DetailViewController.m
if([self.customDelegate respondsToSelector:#selector(getButtonTitile:)])
{
[self.customDelegate getButtonTitile:button.currentTitle];
}
#MasterViewController.m
create obj of DetailViewController
DetailViewController *obj = [[DetailViewController alloc] init];
obj.customDelegate = self;
[self.navigationController pushViewController:reportTypeVC animated:YES];
and add delegate method in MasterViewController.m for get button title.
#pragma mark -
#pragma mark - Custom Delegate Method
-(void) getButtonTitile:(NSString *)btnTitle;
{
NSLog(#"%#", btnTitle);
}
can't understand what's wrong in this case, so I cant use the delegate - there is an exception in self.plistManager.delegate = self; Property 'delegate' not found on object of type 'DataPlistManager *'
#import "DataManager.h"
#import "DataPlistManager.h"
#interface DataAdapter : NSObject <DataStorageManager>
#property (nonatomic,strong) DataPlistManager *plistManager;
- (void) saveFile;
#end
and its implementation
#import "DataAdapter.h"
#implementation DataAdapter
-(id) initWithDataPlistManager:(DataPlistManager *) manager
{
self = [super init];
self.plistManager = manager;
self.plistManager.delegate = self;
return self;
}
- (void) saveFile
{
[self.plistManager savePlist];
}
#end
Your DataPlistManager needs a property delegate:
#property (weak) id<DataStorageManager> delegate;
If you add #import "DataAdapter.h" in your "DataPlistManager.h" file then remove it and add it to "DataPlistManager.m" file, I don't know but some days ago i have same issue, and i solved it by using this trick :)
DataManager class contains delegate property so you should set your object as delegate of DataManager class and call method (send message) saveFile inside delegate class:
#implementation DataAdapter
- (void)someMethod) {
DataManager *dataManagerObject = [[DataManager alloc] init];
dataManagerObject.delegate = self;
}
#implementation DataManager
- (void)someDelegateMethod {
[self.delegate saveFile];
}
Are you sure you understand concept of delegation pattern?
https://developer.apple.com/library/ios/documentation/general/conceptual/CocoaEncyclopedia/DelegatesandDataSources/DelegatesandDataSources.html
I have looked through the other topics on this matter and I have not been able to determine my error.
I am very new to IOS programming. I am trying to create a program that looks at the selected state of 2 buttons and determines whether the buttons selected state are the same.
I am currently trying to use a model to determine the buttons selected state and then pass the state to a label. I have an error which says:
No visible #interface for 'MatchTest' declares the selector 'doesItMatch'
I'd appreciate any help that may be offered.
Thanks!
this is the MatchTest.h file
// MatchTest.h
#import <Foundation/Foundation.h>
#interface MatchTest : NSObject
#end
this is the MatchTest.m file
// MatchTest.m
#import "MatchTest.h"
#implementation MatchTest
-(NSString*)doesItMatch:(UIButton *)sender
{
NSString* tempString;
if(sender.isSelected)
{
tempString = #"selected";
}
else
{
tempString = #"not selected";
}
return tempString;
}
#end
this is the MatchViewController.h file
// MatchViewController.h
#import <UIKit/UIKit.h>
#import "MatchTest.h"
#interface MatchViewController : UIViewController
#end
this is the MatchViewController.m file
// MatchViewController.m
#import "MatchViewController.h"
#interface MatchViewController ()
#property (weak, nonatomic) IBOutlet UILabel *matchLabel;
#property (strong, nonatomic) MatchTest *match;
#end
#implementation MatchViewController
-(MatchTest *)match
{
if(!_match) _match = [[MatchTest alloc] init];
return _match;
}
- (IBAction)button:(UIButton *)sender
{
sender.selected = !sender.isSelected;
self.matchLabel.text = [self.match doesItMatch:sender];
}
#end
declare doesItMatch method in MatchTest.h file
like
in MatchTest.h
-(NSString*)doesItMatch:(UIButton *)sender;
compiler is not able to file doesItMatch method's declaration in .h file that's why that error is there.
You have not defined your method -(NSString*)doesItMatch:(UIButton *)sender in MatchTest.h file.
You are importing MatchTest.h file in MatchViewController.h file so you need to define your methods or variables or property to make available this method.
Therefore according to your error log viewController wasn't able to find the interface where this method is declared.