using method from another class - objective-c

I tried to add picture to my NSView with calling method from another class.
How I must init firstClass instance in secondClass?
Code example:
firstClass.m:
//method for adding picture
-(void) createPoint:(NSPoint)location{
point = [NSImage imageNamed:#"point3"];
point.size = NSMakeSize(21, 21);
pView = [[NSImageView alloc] init];
[pView setFrameSize:crimePoint.size];
[pView setImage:crimePoint];
[pView setFrameOrigin:CGPointMake(location.x-10, location.y-10)];
[self addSubview:pView];
}
secondClass.m:
- (IBAction)updateButton:(id)sender {
[firstC createPoint:NSMakePoint(300, 300)]; // FirstClass* firstC; (alloced and inited)
}
This one looking same, but i don't understand how to use that answer:
Calling Method From Another UIViewController Has No Visible Effect

Related

Class method used in [Rectangle class]

What is the method "class" for, as used in [Rectangle class]? Does it create an instance of Rectangle? I thought that was
Rectangle *aRectangle = [[Rectangle alloc] init].
Why/When would I ever use [Rectangle class]?
Here are probably the two most common uses for [Rectangle class]:
You can use [Rectangle class] to check whether an object is an instance of Rectangle (or an instance of a subclass of Rectangle):
if ([object isKindOfClass:[Rectangle class]]) {
Rectangle *rect = (Rectangle *)object;
// ... use rect
}
But if you just have one message to send, it might be better to just check whether the object understands the message you want to send it:
if ([object respondsToSelector:#selector(area)]) {
double area = [object area];
// etc.
}
You can use the class object to create an instance of the class:
Class rectangleClass = [Rectangle class];
Rectangle *rectangle = [[rectangleClass alloc] init];
Why would you want to do that? Well, if you know the class explicitly at the location (in your code) where you want to create it, you wouldn't. You'd just say [[Rectangle alloc] init], for example.
But consider UIView. Every UIView creates and manages a CALayer. By default, it creates an instance of CALayer, but you might want your view to use a CAShapeLayer (example) or a CAGradientLayer (example) instead. You need a way to tell UIView to create an instance of a different class.
You can tell your UIView subclass what kind of layer to create by overriding the layerClass class method:
#implementation MyShapeView
+ (Class)layerClass {
return [CAShapeLayer class];
}
When it's time for a MyShapeView to create its layer, it'll send itself layerClass and create an instance of whatever class it gets back. The code probably looks something like this:
#implementation UIView {
CALayer *_layer;
}
- (CALayer *)layer {
if (_layer == nil) {
_layer = [[[self layerClass] alloc] init];
_layer.delegate = self;
}
return _layer;
}

Can not call class method

I'm building a tag-based application and want to call the same function from each tab (ViewController).
I'm trying to do it in the following way:
#import "optionsMenu.h"
- (IBAction) optionsButton:(id)sender{
UIView *optionsView = [options showOptions:4];
NSLog(#"options view tag %d", optionsView.tag);
}
optionsMenu.h file:
#import <UIKit/UIKit.h>
#interface optionsMenu : UIView
- (UIView*) showOptions: (NSInteger) tabNumber;
#end
optionsMenu.m file:
#import "optionsMenu.h"
#implementation optionsMenu
- (UIView*) showOptions:(NSInteger) tabNumber{
NSLog(#"show options called");
UIView* optionsView = [[UIView alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
optionsView.opaque = NO;
optionsView.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:0.5f];
//creating several buttons on optionsView
optionsView.tag = 100;
return optionsView;
}
#end
The result is that i never get the "show options called" debug message and thus optionsView.tag is always 0.
What am i doing wrong?
I understand this is most probably an easy and stupid question, but i am not able to solve it myself.
Any feedback is appreciated.
First thing to note is that this is an instance method (and not a Class method as described in the question title). This means that in order to call this method you should have alloc/init an instance of your Class and send the message to the instance. For example:
// Also note here that Class names (by convention) begin with
// an uppercase letter, so OptionsMenu should be preffered
optionsMenu *options = [[optionsMenu alloc] init];
UIView *optionsView = [options showOptions:4];
Now, if you just want to create a Class method that returns a preconfigured UIView, you could try something like this (provided that you do not need access to ivars in your method):
// In your header file
+ (UIView *)showOptions:(NSInteger)tabNumber;
// In your implementation file
+ (UIView *)showOptions:(NSInteger)tabNumber{
NSLog(#"show options called");
UIView *optionsView = [[UIView alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
optionsView.opaque = NO;
optionsView.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:0.5f];
//creating several buttons on optionsView
optionsView.tag = 100;
return optionsView;
}
And finally send the message like this:
UIView *optionsView = [optionsMenu showOptions:4]; //Sending message to Class here
Finally do not forget of course to add your view as a subview in order to display it.
I hope that this makes sense...

Setting Bool in different classes

I have the following code where after a bool is true I want to add a drawing to my rect. here is the code I have but for some reason it is either not setting the bool or calling the setNeedsDisplay. Am I referencing to the other class properly? thanks
//in AppController.m
-(IBAction)colorToggle:(id)sender
{
if ([colorFilter state] == NSOnState)
{
CutoutView *theView = [[CutoutView alloc] init];
[theView setFilterEnabled:YES];
}
}
//in cutoutView.m
- (void)drawRect:(NSRect)dirtyRect
{
[[[NSColor blackColor]colorWithAlphaComponent:0.9]set];
NSRectFill(dirtyRect);
//this is what i want to be drawn when my bool is true and update the drawRect
if (filterEnabled == YES) {
NSRectFillUsingOperation(NSMakeRect(100, 100, 300, 300), NSCompositeClear);
[self update];
}
}
-(void)update
{
[self setNeedsDisplay:YES];
}
OK, you know how not every UILabel is the same? Like, you can remove one UILabel from a view without all the others disappearing too? Well, your CutoutView is the same way. When you write CutoutView *theView = [[CutoutView alloc] init]; there, that creates a new CutoutView that isn't displayed anywhere. You need to talk to your existing CutoutView (probably by hooking up an outlet, but there are any number of perfectly valid designs that will accomplish this goal).
You are forgetting to call the drawRect: method, it should looks like this:
CutoutView *theView = [[CutoutView alloc] init];
[theView setFilterEnabled:YES];
[theView setNeedsDisplay];
From the docs:
When the actual content of your view changes, it is your
responsibility to notify the system that your view needs to be
redrawn. You do this by calling your view’s setNeedsDisplay or
setNeedsDisplayInRect: method of the view.

Working on custom component: subclass UIView or UIViewController?

I'm working on a custom implementation of UISegmentedControl.
I'd like to create a component that able to receive config data and from which obtain a custom View similar to UISegmentedControl.
I started subclassing a UIView and i can create a custom UISegmentedControl with this code:
CustomSegment *segment = [[CustomSegment alloc]
initWithTitles:[NSArray arrayWithObjects:#"one",#"two",nil]];
[self.window addSubview:segment];
But now i'd like to improve my class and add some more customizable parameters to it.
For example i'd like add a custom separators, define the button fonts and so on... here my doubt:
Is it better to work on a UIView subClass or you suggest me to subclass a UIViewController, where i can manage View hierarchy in method like -(void)loadView and -(void)viewDidLoad ?
In a simple UIView subclass, when i launch the custom init method, i setup immediately subviews... while using a UIViewController i can call custom init and define how my subview is builded into -(void)loadView.
Don't use an UIViewController, just extend the UIView class like you did and keep extending its functionality.
Remember to save a pointer to each subview you add (i.e. buttons) in order to be able to access them later.
Define custom setters, for example, a custom setter for changing a button label title would be:
- (void) setButton1Title:(NSString*)str forState:(UIControlState)state{
//You can add some control here
if ([str length] > 20) return;
[_button1 setTitle:str forState:state]; //_button1 is my reference to the button
}
And so on. Don't provide direct access to your subviews, use methods instead.
Also, you can use "layoutSubviews" method to define how your views are going to be displayed in your custom view.
Hope it helps you.
Edit: In your case, I don't see why using lauoutSubviews method but I want to show you what I was trying to say.
Lets say that for example I need to create an UIView class to represent a "Contact" object in my application.
This is what I would do:
#interface ContactView : UIView{
UILabel* _nameLabel;
UILabel* _ageLabel;
Contact* _contact;
}
#property (retain) Contact* contact;
#end
#implementation ContactView
#synthetize contact = _contact;
-(id)initWithContact:(Contact*)c{
self = [super init];
if (self) {
_nameLabel = [[UILabel alloc] init];
_nameLabel.frame = CGRectZero;
[self addSubview:_nameLabel];
[_nameLabel release];
_ageLabel = [[UILabel alloc] init];
_ageLabel.frame = CGRectZero;
[self addSubview:_ageLabel];
[_ageLabel release];
self.contact = c;
}
}
- (void) layoutSubviews{
[super layoutSubviews];
_nameLabel.frame = CGRectMake(0.0f, 0.0f, 200.0f, 25.0f);
_ageLabel.frame = CGRectMake(0.0f, 25.0f, 200.0f, 25.0f);
if (self.contact){
_nameLabel.text = self.contact.name;
_ageLabel.text = self.contact.age;
}else{
_nameLabel.text = #"Unavailable";
_ageLabel.text = #"Unavailable";
}
}
- (void) setContact:(Contact*)c{
self.contact = c;
[self layoutSubviews];
}
#end
Check out how the "layoutSubiews" is used to set the correct frame and data to the labels.
Usually, I use it a lot when creating custom UITableViewCells where you have to reuse the view.
Let me know if I'm being confusing.

Displaying an NSString on a Custom View

I have an interface that has an NSTextField, NSButton, and an NSView. When I type something in the NSTextfield and press the button, I want the text to be drawn in the NSView. So far I have everything connected and working, except for the view.
How can I connect the text and the view so that every time I press the button, the text is drawn to the view?
How can I connect the text and the view so that every time I press the button, the text is drawn to the view?
Views do their own drawing.
You need to give the view the string to draw, and then set the view as needing display. You'll do these in the action method that you wire the button up to.
First, your custom view class needs to have a property for the value (string, in this case) that it's going to display. From your action method, which should generally be on a controller object, send the view object a setFoo: message (assuming you named the property foo). That takes care of job one: The view now has the value to display.
Job two is even easier: Send the view a setNeedsDisplay: message, with the value YES.
That's it. The action method is two lines.
Of course, since views draw themselves, you also need your custom view to actually draw, so you need to implement the drawRect: method in that class. It, too, will be short; all you need to do is tell the string to draw itself.
Bindings
http://developer.apple.com/mac/library/documentation/cocoa/Conceptual/CocoaBindings/Concepts/WhatAreBindings.html#//apple_ref/doc/uid/20002372-CJBEJBHH
For simplicity's sake I didn't mention this before, but the app also has a speech element to speak the string. This aspect of the program works fine, so just ignore any messages involving the SpeakAndDraw class (it's actually misnamed and only includes a speech method, nothing about drawing).
View.m
#import "View.h"
#implementation View
#synthesize stringToDraw;
- (id)initWithFrame:(NSRect)frame {
self = [super initWithFrame:frame];
if (self) {
[self setAttributes];
stringToDraw = #"Hola";
}
return self;
}
- (void)drawRect:(NSRect)dirtyRect {
NSRect bounds = [self bounds];
[self drawStringInRect:bounds];
}
- (void)setAttributes
{
attributes = [[NSMutableDictionary alloc] init];
[attributes setObject:[NSFont fontWithName:#"Helvetica"
size:75]
forKey:NSFontAttributeName];
[attributes setObject:[NSColor blackColor]
forKey:NSForegroundColorAttributeName];
}
- (void)drawStringInRect:(NSRect)rect
{
NSSize strSize = [stringToDraw sizeWithAttributes:attributes];
NSPoint strOrigin;
strOrigin.x = rect.origin.x + (rect.size.width - strSize.width)/2;
strOrigin.y = rect.origin.y + (rect.size.height - strSize.height)/2;
[stringToDraw drawAtPoint:strOrigin withAttributes:attributes];
}
#end
SpeakerController.m
#import "SpeakerController.h"
#implementation SpeakerController
- (id)init
{
speakAndDraw = [[SpeakAndDraw alloc] init];
view = [[View alloc] init];
[mainWindow setContentView:mainContentView];
[mainContentView addSubview:view];
return self;
}
- (IBAction)speakText:(id)sender
{
[speakAndDraw setStringToSay:[text stringValue]];
[speakAndDraw speak];
[view setStringToDraw:[text stringValue]];
[view setNeedsDisplay:YES];
NSLog(#"%#", view.stringToDraw);
NSLog(#"%#", [view window]);
}
#end