Edit:
I'm drawing a line using drawRect: function which resides in a custom class in a view which I created in the MainStoryboard.storyboard file. The view does point to the custom class (draw2D) in the interface builder.
All code i have regarding draw in my main file(viewController) is now:
(header file)
#class draw2D;
#property (weak, nonatomic) IBOutlet draw2D *draw;
(m file)
#import "draw2D.h"
[draw.listOfFreqToDraw addObject: closestChar];
[draw setNeedsDisplay];
The problem I seem to have now is that it only runs the drawRect method in draw2D class once and never calls it again (therefor listOfFreqToDraw isn't even called after the first run)
You can always change a variable in draw2D
Set this up in the draw2D.h
#property (nonatomic, strong) NSMutableArray * listOfFreqToDraw;
in draw2D.m
- (void)drawRect:(CGRect)rect {
for (UIBezierPath *path in self. listOfFreqToDraw) {
[path stroke];
}
}
and in your main class
[draw.listOfFreqToDraw addObject: closestChar];
[draw setNeedsDisplay];
Related
I am converting some Swift code to Objective C. not much familiar with Swift syntax.
override var layer: CAShapeLayer {
get {
return super.layer as! CAShapeLayer
}
}
I don't understand how to override this property in objective C.
I tried this
in .h file
#property (nonatomic, readonly, retain) CAShapeLayer *layer;
in .m file
#synthesize layer;
but it seems to not work. There is no error but the code is not executing as expected.
What you need to do now is just implement the getter for the layer property:
-(CAShapeLayer *)layer
{
return (CAShapeLayer *)super.layer
}
I have UIViewController named ParentViewController.h and .m
Then I added UIView inside this ParentViewController.
I had uiview.h and uiview.h added and assigned to UIView inside ParentViewController.
From
-(void)drawRect:(CGRect)rect {}
which is located in uiview.m, I need to access to properties inside ParentViewController.
How do I do this? Am I using UIView wrong?
ParentViewController.h
#import <UIKit/UIKit.h>
#interface ParentViewController : UIViewController
//I want my uiview to access this variable.
#property (nonatomic, strong) NSMutableArray *usedByUIView;
#end
ParentViewController.m
#import "ParentViewController.h"
#import "uiview.h"
#implementation ParentViewController
- (void)viewDidLoad {
...
}
#end
uiview.h
#import <UIKit/UIKit.h>
#interface uiview : UIView
#end
uiview.m
#import "uiview.h"
#implementation uiview
-(id) initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if(self){
}
return self;
}
- (void)drawRect:(CGRect)rect {
NSLog(#"start drawing using the data from usedByUIView");
}
#end
There are a few answers on this subject but, summarizing them, you don't, at least not the way that you're doing it. UIView's do not have access to their view controller's and aren't supposed to need access. Of course, in the real world, sometimes it's not worth the overhead of coding around independent views so people hack in access to the controller access. This can be done by keeping an instance variable in the view, pointing to the controller, and assigning a reference to it after the view has loaded, or by overriding the init so you also pass a view controller, or lots of other ways. But before you do that think through the logic of why you want access to the controller from the view and see if there isn't a different way to do it.
Right now I have a custom view class called OTGMarkerDetailView which inherits from UIView and a corresponding .xib with it. It just has two text labels and I've linked the text labels to the text label IBOutlets in OTGMarkerDetailView.m.
OTGMarkerDetailsView.h:
#import <UIKit/UIKit.h>
#interface OTGMarkerDetailView : UIView
- (void)setLabelsWithMainAddress:(NSString *)mainAddress subAddress:(NSString *)subAddress;
#end
OTGMarkerDetailView.m
#import "OTGMarkerDetailView.h"
#interface OTGMarkerDetailView ()
#property (nonatomic, strong) IBOutlet UILabel *mainAddressLabel;
#property (nonatomic, strong) IBOutlet UILabel *subAddressLabel;
#end
#implementation OTGMarkerDetailView
- (void)setLabelsWithMainAddress:(NSString *)mainAddress subAddress:(NSString *)subAddress {
NSLog(#"%#", self.mainAddressLabel.text);
self.mainAddressLabel.text = mainAddress;
self.subAddressLabel.text = subAddress;
NSLog(#"%#", self.mainAddressLabel.text);
}
#end
I load it in another view as a subview, using initWithFrame. But the console always logs null when I try to set the text label values, and when I use a breakpoint it seems the mainAddressLabel and the subAddressLabel are nil themselves. Did I do something wrong in linking the xib to the view? What am I missing? Thanks.
I found a work around. I have created a custom UIView.
1.
I attached Nib file to it in initWithFrame method
CustomView *nibView;
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
NSArray *array = [[NSBundle mainBundle] loadNibNamed:#"CustomView" owner:self options:nil];
nibView = [array objectAtIndex:0];
[self addSubview:nibView];
}
return self;
}
You can see clearly, I haven't created the instance of UIView instead I created nibView of the same class type.
2.
Now creating IBOutlet properties and work on it. In customView.m file.
#interface FTEndorsedExpandedView : UIView
#property (retain) IBOutlet UILabel *label;
#end
3.
Create functions to set title or changing properties. (in customView.m file). Use nibView to access the properties rather than using self.label
-(void)setLabelText:(NSString*)string{
[nibView.label setText:string];
}
When you create your custom view in another view using initWithFrame a new instance of your custom class is created. This instance is not the same one you have in interface builder and hence the label properties are nil for this newly created instance. In order to solve this problem either put your view in its parent view in interface builder with its connection attached or override initWithFrame for your custom view and initialise your labels in there.
I've managed to setup a custom UIView class with a nib.
My .h looks like
#interface MyView : UIView <UITextFieldDelegate>
#property (nonatomic, weak) IBOutlet UITextField *textField;
#property (nonatomic, strong) MyView *topView;
And .m
#implementation MyView
NSString *_detail;
-(id)initWithCoder:(NSCoder *)aDecoder{
if ((self = [super initWithCoder:aDecoder])&&self.subviews.count==0){
MyView *v = [[[NSBundle mainBundle] loadNibNamed:#"MyView" owner:self options:nil] objectAtIndex:0];
self.textField = v.textField;
if (self.topView == nil)self.topView = self;
v.topView = self.topView;
[self addSubview:v];
}
return self;
}
-(NSString *)topDetail{
return _detail;
}
-(NSString *)detail{
return [self.topView topDetail];
}
-(void)setTopDetail:(NSString *)detail{
_detail = detail;
}
-(void)setDetail:(NSString *)detail{
[self.topView setTopDetail:detail];
}
- (BOOL)textFieldShouldReturn{
//here I show an UIAlertView using self.detail for the message
}
Note: The setup I have works exactly how I want it to.
The problem
What I would like to do is remove my manual detail methods and turn NSString *_detail into #property (...)NSString *detail
When I try it with the #property, then within my ViewController if i call
myView.detail = someString, myView will be referring to the top most view. Then if textFieldShouldReturn gets called because of user interaction, then it calls the nested MyViews _detail which has not been set.
What I want:
To not have to write extra code for access to _detail regardless of where I'm accessing it from. I want to merely declare the property and go on with my usual coding.
Your problem is that you're trying to keep the a class reference, topView, with an object property.
In other words every objects' topView is the object itself, which makes no sense.
Your definition should be:
#interface MyView : UIView <UITextFieldDelegate>
// Class "properties"
+ (instancetype)topview;
+ (void)setTopView:(UIView *)topView;
// Object properties
#property (nonatomic, weak) IBOutlet UITextField *textField;
#property (nonatomic, strong) NSString *detail;
Now you can keep track of the topView:
static MyView * _topView;
#implementation MyView
+ (instancetype)topView {return _topView}; // You could also create one here lazily
+ (void)setTopView:(UIView *)topView { _topView = topView };
-(id)initWithCoder:(NSCoder *)aDecoder{
if ((self = [super initWithCoder:aDecoder])&&self.subviews.count==0){
JUITextFieldHint *v = [[[NSBundle mainBundle] loadNibNamed:#"JUITextFieldHint" owner:self options:nil] objectAtIndex:0];
self.textField = v.textField;
if ([MyView topView] == nil)[MyView setTopView:self];
v.topView = self.topView;
[self addSubview:v];
}
return self;
}
No more need for manual setters and getters. Now you can use your detail property, either with anyInstance.detail or [MyView topView].detail, or even MyView.topView.detail if you like dots like me ;)
You're init method still looks weird but should work. Check Apples init template.
Lastly, textField can be weak as long as it has a superview, otherwise make it strong.
My xib contained one UIView (no controller). I had the UIView set to MyView for the class.
I changed the UIView back to just UIView then set File's Owner to MyView. This solved issues of recursion (which is why I had such a weird setup in the first place) and caused my variables and IBOutlets to be linked up properly.
Credit goes to How do I create a custom iOS view class and instantiate multiple copies of it (in IB)? and some of the comments which I missed the first couple times I read through it.
Got away from XCode programming for a while, now I'm starting back and feel like I'm starting ALL over. I have a simple example that's driving me crazy.
I have created a sub class of UIView called Word1View and added it to my storyboard.
I declared it as a property in the main view controller and attached it as an IBOutlet to the main view. I can draw on this view using Core Graphics with no problems (rectangles, lines, etc). Here's the code in the ".h" file. The property is synthesized correctly in the ".m"
#import <UIKit/UIKit.h>
#import "Word1View.h"
#interface Board3ViewController : UIViewController
{
Word1View *word1View;
}
#property (nonatomic, strong) IBOutlet Word1View *word1View;
#end
Now, here's the problem. I have added a UILabel (I will be adding UIImageFiles later)
in Word1View.h it appears as so:
#import <UIKit/UIKit.h>
#interface Word1View : UIView
{
UILabel *testLabel;
}
#property (nonatomic, retain) UILabel *testLabel;
#end
This property is also synthesized correctly. The UILabel was added to the view in the main storyboard. I tried to make this an IBOutlet, but could not hook it up as long as it was part of the subview. I tried to access the UILabel in my main view controller as so:
[super viewDidLoad];
[self.view addSubview:word1View];
NSLog(#"Label text is: %#", word1View.testLabel.text);
I don't have any access to that label as evidenced by the output to NSLog which is:
Board3[14520:c07] Label text is: (null)
I would like to be able to access the label (change its text, properties etc) from my main View Controller.
Any help is greatly appreciated. Thank you.
You need to instantiate your UILabel and give it some text.
wordView1 = [[UILabel alloc] init];
wordView.text = #"Some Text";