addSubview with NSObject? - iphone

I have a class which is an NSObject type, and in a view it won't let me put:
[self.view addSubview:nsObject];
because it's an incompatible type. How can i get this to work?

The addSubview: method only takes instances of UIView. It won't work with NSObject.
Check out the method specification in the Apple Docs

You need the object you're adding to be of the type UIView or inherit from it. In your class declaration, simply put:
#interface MyClasS : UIView {

I assume that nsSubview is a subclass of UIView and just by typing, arg passing the compiler is seeing it as an NSObject? Or is it some kind of wrapper object that contains a UIView? You could try:
UIView *v = (UIView *)nsSubview ;
[ self.view addSubview:v] ;

Related

getting warning in uitextfield's delegate

I'm new in iphone development.now, I'm facing one warning in my project.while,setting the delegate of UITextfield in ios 6 I'm getting the warning that
"**incompatible pointer types sending 'class' to parameter of type '<uitextfielddelegate>'**"
+(UITextField*)tableLabelForText:(NSString *)txt frame:(CGRect)frm isEditable:(BOOL)isEditable
{
UITextField *txtField = [[UITextField alloc] initWithFrame:frm];
[txtField setEnabled:isEditable];
[txtField setText:txt];
[txtField setTextColor:[UIColor blackColor]];
[txtField setDelegate:self];
return txtField;
}
You are trying to assign the delegate in a class method which has no idea of the initialised object. Hence the warning. What you need to do is setDelegate to the initialised object.
[txtField setDelegate:<MyObject>];
Or you can as one of the answers suggests change the class methods to instance method.
-(UITextField*)tableLabelForText:(NSString *)txt frame:(CGRect)frm isEditable:(BOOL)isEditable
You are using a Class level method "+" to return a text field instance, change it to Instance Level Method "-". i.e:
-(UITextField*)tableLabelForText:(NSString *)txt frame:(CGRect)frm isEditable:(BOOL)isEditable
If I am not wrong , you are setting Delegate for an NSObject class ,
as NSObject class does not have any views , so UITextFieldDelegate does not confirms to the class. Instead use UIView
#interface ClassName : UIView <UITextFieldDelegate>

"Subclassing" a variable in Objective-C [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Objective C — narrow instance variable types in subclasses?
I have a class called ParentClass which has a UIView property. I also have a class called ChildClass which is a subclass of ParentClass. ChildClass obviously inherits the UIView property, but in ChildClass I know for certain I'll only be using a UIScrollView for this property.
My question is, is it possible / feasible to somehow "subclass" the UIView property, rename it, and make it so it can only be a UIScrollView? Would I have to override the property in the .m file when I synthesize?
Similar to how a UITableViewController's main view property is a UITableView rather than a UIView as in UIViewController.
UPDATE: Maybe I just didn't mean property, but also the variable itself.
Just add a property with the same name to your child class but with UIScrollView instead of UIView.
If you're subclassing ParentClass, that has a property of a UIView and you need ChildClass to inherit a UIScrollView.. You should just make a UIScrollView property in ParentClass so ChildClass can inherit and use it.
If ChildClass isn't going to use the UIView property, if you never initialize it will remain nil therefor not using up any of your memory. Also giving you the benefit, if and or when you choose to use the UIView property you can.
Alternatively, simply declare a new UIScrollView property in ChildClass if you don't want to in ParentClass
Hope this made sense, and helps !
Properties are converted into methods, and these methods can be overridden just like any other. You can do something like this:
#interface ParentClass {
NSView* myView;
}
#property(retain) NSView* myView;
#end
#implementation ParentClass
#synthesize myView;
#end
#interface ChildClass
#end
#implementation ChildClass
-(void) setMyView:(NSView*)v;
{
if([v isKindOfClass:[UIScrollView class]]){
[super setMyView:v];
} else {
//do whatever error handling you want to here
}
}
#end
The -setMyView: method is one of the methods that the property was converted into, so defining it in ChildClass will override the one on the parent class.
Side note: when you refer to "subclassing" the property, the correct term is "overriding."

Multiple delegates per one object?

I have a UIScrollView that I need to subclass and within the subclass I need to attach the UIScrollViewDelegate so I can implement the viewForZoomingInScrollView method.
Then I have a UIViewController where I need to instantiate an object of this UIScrollView subclass that I created, and I would also like to make the UIViewController a UIScrollViewDelegate for this object so I can implement scrollViewDidZoom in this UIViewController class.
How is it possible to make one object have two delegates? (I know I could easily just have one delegate and just implement both methods there, but for design purposes I'd like to do it the way that I'm mentioning).
Sometimes it makes sense to attach several delegates to a scroll view. In that case you can build a simple delegation splitter:
// Public interface
#interface CCDelegateSplitter : NSObject
- (void) addDelegate: (id) delegate;
- (void) addDelegates: (NSArray*) delegates;
#end
// Private interface
#interface CCDelegateSplitter ()
#property(strong) NSMutableSet *delegates;
#end
#implementation CCDelegateSplitter
- (id) init
{
self = [super init];
_delegates = [NSMutableSet set];
return self;
}
- (void) addDelegate: (id) delegate
{
[_delegates addObject:delegate];
}
- (void) addDelegates: (NSArray*) delegates
{
[_delegates addObjectsFromArray:delegates];
}
- (void) forwardInvocation: (NSInvocation*) invocation
{
for (id delegate in _delegates) {
[invocation invokeWithTarget:delegate];
}
}
- (NSMethodSignature*) methodSignatureForSelector: (SEL) selector
{
NSMethodSignature *our = [super methodSignatureForSelector:selector];
NSMethodSignature *delegated = [(NSObject *)[_delegates anyObject] methodSignatureForSelector:selector];
return our ? our : delegated;
}
- (BOOL) respondsToSelector: (SEL) selector
{
return [[_delegates anyObject] respondsToSelector:selector];
}
#end
Then simply set an instance of this splitter as a delegate of the scroll view and attach any number of delegates to the splitter. All of them will receive the delegation events. Some caveats apply, for example all the delegates are assumed to be of the same type, otherwise you’ll have trouble with the naive respondsToSelector implementation. This is not a big problem, it’s easy to change the implementation to only send delegation events to those who support them.
You don't want an object with 2 delegates. You want to keep your customScrollView keep the responsibility of its own UIScrollViewDelegate functions.
To make your parentVC respond to the delegate methods of UIScrollView as well you will have to make a custom delegate inside your customScrollView.
At the moment a UIScrollViewDelegate function gets called you will also call one of your delegate functions from your custom delegate. This way your parentVC will respond at the moment you want it to.
It will look somewhat like this.
CustomScrollView.h
#protocol CustomDelegate <NSObject>
//custom delegate methods
-(void)myCustomDelegateMethod;
#end
#interface CustomScrollView : UIScrollView <UIScrollViewDelegate>
{
id<CustomDelegate> delegate
//the rest of the stuff
CustomScrollView.m
-(void) viewForZoomingInScrollView
{
[self.delegate myCustomDelegateMethod];
//rest of viewForZoomingInScrollView code
ParentVC.h
#interface CustomScrollView : UIViewController <CustomDelegate>
{
//stuff
ParentVC.m
-(void)makeCustomScrollView
{
CustomScrollView *csv = [[CustomScrollView alloc] init];
csv.delegate = self;
//other stuff
}
-(void)myCustomDelegateMethod
{
//respond to viewForZoomingInScrollView
}
I hope this fully covers your problem.
Good luck.
Short answer: you don't. Delegates are typically a weak one-to-one relationship:
#property (nonatomic, weak /*or assign*/) id<MyViewDelegate> delegate;
Sometimes you will see a "listener" design pattern, which is the one-to-many form of delegates:
- (void) addListener:(id<MyViewListener>)listener;
- (void) removeListener:(id<MyViewListener>)listener;
In your case, there doesn't appear to be a nice public override point in UIScrollView that allows subclasses to specify the viewForZoomingInScrollView. I would avoid making the UIScrollView its own delegate, if possible. You could make the UIViewController the UIScrollViewDelegate and have it provide the viewForZooming. Or you could make an intermediate view subclass which uses UIScrollView, provides the viewForZooming, and forwards the other delegate methods up.
I don't think you can have two UIScrollViewDelegate delegates directly connected to the same object.
What you can do is having the two delegates chain-connected. I.e., you connect one delegate to the other, then have the former forward messages to the latter when it cannot handle them itself directly.
In any case, I think I am missing a bit to fully suggest a solution, namely the reason why you do need a second delegate and cannot do always through one single delegate. In other words, what I think is that there might be alternative designs that would avoid needing two delegates.
Here's another potential problem with what you're trying to do...
Let's say you have two instances of a UIScrollView and one delegate object. In the delegate object, you override scrollViewDidScroll(UIScrollView *): method of the UIScrollViewDelegate protocol.
Inside the method, you want to access the value of the contentOffset property of both scroll views because, perhaps, you have two adjacent collections views, and you're trying to get the index path of the item at the center of the collection view to get the values of properties associated with those two items (think UIDatePicker).
In that case, how do you different between scroll views? The scrollView property only refers to one scroll view; but, even if it referred to both, how do you get the value of their respective contentOffset properties?
Now, you might say, "I can create an IBOutlet for both, and use their assigned references instead of the scrollView property in the delegate method, such as self.collectionViewFirst.contentOffset and self.collectionViewSecond.contentOffset, and ignore the scrollView property of the delegate method.
The problem is this: that property isn't stored. It's only available when the delegate method is called. Why? Because there's only one delegate object, and only one contentOffset property. By scrolling another scroll view, the value of the contentOffset property would change, and not reflect the content offset of any other scroll view except the last one scrolled.
It's bad practice to do what you're trying to do, even if the case (or a case like it) as I described doesn't apply to your situation. Remember: writing code is about sharing code. Incorrect code sends a message to others that diminishes your reputation.

cocoa - referencing a method on the parent

I had a method on my main view controller named "calculateThis".
This method was run, obviously, as
int newValue = [self calculateThis:myVariable];
when I run it from inside the view controller.
Then I created a static class and I need to run this method from there.
How do I reference this method from that class using just relative references, as super, superview, delegate, etc. I cannot use the class name defined on the delegate because this static class is used in several apps of mine.
I need to go up in the hierarchy, I imagine one level, and access the method there...
thanks.
Define your utility methods in a category on NSObject or related subclasses of NSObject.
Which you have done.
Adding (id)sender to your method will work. Then your method can reference the object that called it. Something like this.
+(int)calculateThis:(id)sender userInfo:(id)info;
then your call becomes.
int newValue = [NSObject calculateThis:self userInfo:myVariable];
If your intent is to create a class that you can use without initializing it, that's possible using class methods. For instance, if I want to make a class called MyClass with a doSomethingWith: method, I would define the following:
In MyClass.h:
#interface MyClass : NSObject {
}
+(void)doSomethingWith:(id)thisObject;
#end
In MyClass.m:
#import "MyClass.h"
#implementation MyClass
+(void)doSomethingWith:(id)thisObject
{
// Your code goes here.
}
#end
To reference this method in another class, you can use the class object for MyClass like so:
[MyClass doSomethingWith:#"Hello, World!"];
This isn't really a typical Cocoa or Cocoa Touch design pattern, but can be handy for things like calculations.
Are you talking about the superclass? If so, you use [super ...].

Using CALayer Delegate

I have a UIView whose layers will have sublayers. I'd like to assign delegates for each of those sublayers, so the delegate method can tell the layer what to draw. My question is:
What should I provide as CALayer's delegate? The documentation says not to use the UIView the layers reside in, as this is reserved for the main CALayer of the view. But, creating another class just to be the delegate of the CALayers I create defeats the purpose of not subclassing CALayer. What are people typically using as the delegate for CALayer? Or should I just subclass?
Also, why is it that the class implementing the delegate methods doesn't have to conform to some sort of CALayer protocol? That's a wider overarching question I don't quite understand. I thought all classes requiring implementation of delegate methods required a protocol specification for implementers to conform to.
Preferring to keep the layer delegate methods in my UIView subclass, I use a basic re-delegating delegate class. This class can be reused without customization, avoiding the need to subclass CALayer or create a separate delegate class just for layer drawing.
#interface LayerDelegate : NSObject
- (id)initWithView:(UIView *)view;
#end
with this implementation:
#interface LayerDelegate ()
#property (nonatomic, weak) UIView *view;
#end
#implementation LayerDelegate
- (id)initWithView:(UIView *)view {
self = [super init];
if (self != nil) {
_view = view;
}
return self;
}
- (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)context {
NSString *methodName = [NSString stringWithFormat:#"draw%#Layer:inContext:", layer.name];
SEL selector = NSSelectorFromString(methodName);
if ([self.view respondsToSelector:selector] == NO) {
selector = #selector(drawLayer:inContext:);
}
void (*drawLayer)(UIView *, SEL, CALayer *, CGContextRef) = (__typeof__(drawLayer))objc_msgSend;
drawLayer(self.view, selector, layer, context);
}
#end
The layer name is used to allow for per-layer custom draw methods. For example, if you have assigned a name to your layer, say layer.name = #"Background";, then you can implement a method like this:
- (void)drawBackgroundLayer:(CALayer *)layer inContext:(CGContextRef)context;
Note, your view will need a strong reference the instance of this class, and it can be used as the delegate for any number of layers.
layerDelegate = [[LayerDelegate alloc] initWithView:self];
layer1.delegate = layerDelegate;
layer2.delegate = layerDelegate;
The lightest-wight solution would be to create a small helper class in the the file as the UIView that's using the CALayer:
In MyView.h
#interface MyLayerDelegate : NSObject
. . .
#end
In MyView.m
#implementation MyLayerDelegate
- (void)drawLayer:(CALayer*)layer inContext:(CGContextRef)ctx
{
. . .
}
#end
Just place those at the top of your file, immediately below the #import directives. That way it feels more like using a "private class" to handle the drawing (although it isn't -- the delegate class can be instantiated by any code that imports the header).
Take a look at the docs on formal vs informal protocols. The CALayer is implementing an informal protocol which means that you can set any object to be its delegate and it will determine if it can send messages to that delegate by checking the delegate for a particular selector (i.e. -respondsToSelector).
I typically use my view controller as the delegate for the layer in question.
A note regarding "helper" classes for use as a layer's delegate (with ARC at least):
Make sure you store a "strong" reference to your alloc/init'd helper class (such as in a property). Simply assigning the alloc/init'd helper class to the delegate seems to cause crashes for me, presumably because mylayer.delegate is a weak reference to your helper class (as most delegates are), so the helper class gets freed up before the layer can use it.
If I assign the helper class to a property, then assign it to the delegate, my weird crashes go away, and things behave as expected.
I personally voted for Dave Lee's solution above as being the most encapsulating, particularly where you have multiple layers. However; when I tried it on IOS 6 with ARC I got errors on this line and suggesting that I need a bridged cast
// [_view performSelector: selector withObject: layer withObject: (id)context];
I therefore amended Dave Lee's drawLayer method from his re-delegating delegate class to employ NSInvocation as below. All usage and ancillary functions are identical to those Dave Lee posted on his earlier excellent suggestion.
-(void) drawLayer: (CALayer*) layer inContext: (CGContextRef) context
{
NSString* methodName = [NSString stringWithFormat: #"draw%#Layer:inContext:", layer.name];
SEL selector = NSSelectorFromString(methodName);
if ( ![ _view respondsToSelector: selector])
{
selector = #selector(drawLayer:inContext:);
}
NSMethodSignature * signature = [[_view class] instanceMethodSignatureForSelector:selector];
NSInvocation * invocation = [NSInvocation invocationWithMethodSignature:signature];
[invocation setTarget:_view]; // Actually index 0
[invocation setSelector:selector]; // Actually index 1
[invocation setArgument:&layer atIndex:2];
[invocation setArgument:&context atIndex:3];
[invocation invoke];
}
I prefer the following solution. I would like to use the drawLayer:inContext: method of the UIView to render a subview that I might add without adding extra classes all over the place. My solution is as follows:
Add the following files to your project:
UIView+UIView_LayerAdditions.h with contents:
#interface UIView (UIView_LayerAdditions)
- (CALayer *)createSublayer;
#end
UIView+UIView_LayerAdditions.m with contents
#import "UIView+UIView_LayerAdditions.h"
static int LayerDelegateDirectorKey;
#interface LayerDelegateDirector: NSObject{ #public UIView *view; } #end
#implementation LayerDelegateDirector
- (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx
{
[view drawLayer:layer inContext:ctx];
}
#end
#implementation UIView (UIView_LayerAdditions)
- (LayerDelegateDirector *)director
{
LayerDelegateDirector *director = objc_getAssociatedObject(self, &LayerDelegateDirectorKey);
if (director == nil) {
director = [LayerDelegateDirector new];
director->view = self;
objc_setAssociatedObject(self, &LayerDelegateDirectorKey, director, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
return director;
}
- (CALayer *)createSublayer
{
CALayer *layer = [CALayer new];
layer.contentsScale = [UIScreen mainScreen].scale;
layer.delegate = [self director];
[self.layer addSublayer:layer];
[layer setNeedsDisplay];
return layer;
}
#end
Now add the header to your .pch file. If you add a layer using the createSublayer method, it will automagically show up without bad allocs in the override to drawLayer:inContext:. As far as I know the overhead of this solution is minimal.
It's possible to implement a delegation without resorting to a strong ref.
NOTE: The basic concept is that you forward the delegate call to a selector call
Create a selector instance in the NSView you want to get the delegation from
implement the drawLayer(layer,ctx) in the NSView you want to get the delegation from call the selector variable with the layer and ctx vars
set the view.selector to a handleSelector method where you then retrieve the layer and ctx (this can be anywhere in your code, weak or strongly referenced)
To see an example of how you implement the selector construction:(Permalink) https://github.com/eonist/Element/wiki/Progress#selectors-in-swift
NOTE: why are we doing this? because creating a variable outside methods whenever you want to use the Graphic class is non-sensical
NOTE: And you also get the benefit that the receiver of the delegation doesn't need to extend NSView or NSObject
Can you use the passed in layer parameter to construct a switch statement so you can put everything in this method(against the advice of the documents):
-(void) drawLayer: (CALayer*) layer inContext: (CGContextRef) context {
if layer = xLayer {...}
}
Just my 2 cents.