No visible #interface for AVCamViewController declares the selector layer - interface

- (void)setSession:(AVCaptureSession *)session {
((AVPlayerLayer *)[self layer]).videoGravity = AVLayerVideoGravityResizeAspectFill;
((AVPlayerLayer *)[self layer]).bounds = ((AVPlayerLayer *)[self layer]).bounds;
[(AVCaptureVideoPreviewLayer *)[self layer] setSession:session];
}
When I try to use the videogravity code, it shows the error, No visible #interface for AVCamViewController declares the selector layer, on the three bottom lines when it says "self layer" in the AVCAM sample? How do I fix this?

Related

Capture gesture events on MKOverlayView with an UIGestureRecognizer

I try to capture events on a subclassed MKOverlayView with a UIGestureRecognizer.
However the selector never gets fired. Any ideas?
interface:
#import <MapKit/MapKit.h>
#interface XYOverlayView : MKCircleView {}
-(void) viewTapped:(UIGestureRecognizer *)gestureRecognizer;
#end
imp:
#implementation XYOverlayView
- (id)initWithOverlay:(id <MKOverlay>)overlay
{
if(self = [super initWithOverlay:overlay])
{
self.userInteractionEnabled = TRUE;
self.multipleTouchEnabled = TRUE;
UITapGestureRecognizer *tapRecogniser = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(viewTapped:)];
[self addGestureRecognizer:tapRecogniser];
[tapRecogniser release];
}
return self;
}
-(void) viewTapped:(UIGestureRecognizer *)gestureRecognizer
{
NSLog(#"XYOverlayView tapped");
}
#end
you forgot to implement the UIGestureRecognizerDelegate in your interface and you have to import the UIKit
#import <UIKit/UIKit.h>
#interface XYOverlayView : MKCircleView <UIGestureRecognizerDelegate>
Make sure to specify the numberOfTapsRequired and numberOfTouchesRequired otherwise the gesture recognizer doesn't know what to accept as a 'tap'.
tapRecogniser.numberOfTapsRequired = 1;
tapRecogniser.numberOfTouchesRequired = 1;
Did not get this to work. Switched to an custom MKAnnotationView to capture the gestures. This also has the advantage the tapable region in the window stays the same size.
I think my answer here might be a solution: MKOverlayView and touches

Several lines of code, that blows my mind (or NSString "out of scope" dilemma.. again)

I'm totally confused with this small "out of scope" thing.
So here is some code to describe my situation:
Simple iphone view-based application.
View controller header:
#import <UIKit/UIKit.h>
#interface global_nsstring_testViewController : UIViewController {
UIImageView* image_view;
NSString* image_name;
}
#property (nonatomic,retain) UIImageView* image_view;
#property (nonatomic,retain) NSString* image_name;
- (void) fadeView:(UIImageView*)View andThenChangeImageTo:(NSString*)Name;
- (void) switchImageAfterFade;
#end
View controller .m:
#import "global_nsstring_testViewController.h"
#implementation global_nsstring_testViewController
#synthesize image_view, image_name;
- (void) viewDidLoad {
image_view = [[UIImageView alloc] initWithImage:[UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"image1.png" ofType:nil]]];
// ## Block 1 ##
// NSString* name = #"image2.png";
// [self fadeView:image_view andThenChangeImageTo:name];
// ## Block 2 ##
// NSString* name = [NSString stringWithFormat:#"image%d.png",2];
// [self fadeView:image_view andThenChangeImageTo:name];
[self.view addSubview:image_view];
[super viewDidLoad];
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
// ## Block 3 ##
// NSString* name = #"image2.png";
// [self fadeView:image_view andThenChangeImageTo:name];
// ## Block 4 ##
NSString* name = [NSString stringWithFormat:#"image%d.png",2];
[self fadeView:image_view andThenChangeImageTo:name];
}
- (void) fadeView:(UIImageView*)View andThenChangeImageTo:(NSString*)Name {
image_name = Name;
image_view = View; // ## Point 1 ##
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:1];
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:#selector(switchImageAfterFade)];
View.alpha = 0.3;
[UIView commitAnimations];
}
- (void) switchImageAfterFade {
UIImage* image = [UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:image_name ofType:nil]]; // ## Point 2 ##
[image_view setImage:image];
}
- (void) dealloc {
[image_view removeFromSuperview];
[image_view release];
[super dealloc];
}
#end
With uncommented #Block 4# I get “out of scope” message from debugger on image_name var at #Point 1#. And therefore I get EXC_BAD_ACCESS at #Point 2#.
However with uncommented #Block 3# or #Block 1# instead of #Block 4# everything works fine, so I suppose this is all about NSString...
I've tried to use NSMutableString, but without any success either.
So if anyone could tell me, what I do wrong or how to fix it, I would be greatly appreciate.
Another strange thing, that I don't get:
If to uncomment #Block 2# and not to use any breakpoints, it won't crash, but image will disappear. But if I set a breakpoint at #Point 2#, it will crash with EXC_BAD_ACCESS after just one step.
xCode version: 3.2.3
First of all, "out of scope" in the debugger simply means the debugger can't figure out how to display the variable. It's essentially meaningless. You can print the value by clicking on the console (which has "gdb>" in it) and typing
po image_name
Secondly, you are not using setters correctly. You've got #property's for your two variables, but you're not using them. When you do
variable = value;
it's simply setting the variable -- no property methods are called. However,
self.variable = value;
will call the property setter, which since you've got "nonatomic, retain" will retain your variable, and all will be swell.
In this case, you're doing
image_name = Name;
where you want to do
self.image_name = Name;
or (as tob suggests)
image_name = [Name retain];
It's a very common thing when you start doing Objective-C coding that you confuse the two ways to set a variable in a class, and it's vital that you get the difference. Your properties are not called when you do not use instance dot variable.
Coincidentally, a lot of people also tend to confuse this even more by doing things like
self.image_name = [Name retain];
This is absolutely incorrect. You will end up leaking "Name" every time you set image_name, because of the double-retain (once for #property (nonatomic, retain) in your setter, and once for [Name retain]).
Block 4 uses a convenience initializer, so you should use [[NSString stringWithFormat:#"image%d.png",2] retain] or it will get autoreleased.
Don't forget to release it after assigning it with self.image_name = name

Accessing View in awakeFromNib?

I have been trying to set a UIImageView background color (see below) in awakeFromNib
[imageView setBackgroundColor:[UIColor colorWithRed:0 green:0 blue:0 alpha:1.0]];
When it did not work, I realised that its probably because the view has not loaded yet and I should move the color change to viewDidLoad.
Can I just verify that I have this right?
gary
EDIT_002:
I have just started a fresh project to check this from a clean start. I setup the view the same as I always do. The results are that the controls are indeed set to (null) in the awakeFromNib. Here is what I have:
CODE:
#interface iPhone_TEST_AwakeFromNibViewController : UIViewController {
UILabel *myLabel;
UIImageView *myView;
}
#property(nonatomic, retain)IBOutlet UILabel *myLabel;
#property(nonatomic, retain)IBOutlet UIImageView *myView;
#end
.
#synthesize myLabel;
#synthesize myView;
-(void)awakeFromNib {
NSLog(#"awakeFromNib ...");
NSLog(#"myLabel: %#", [myLabel class]);
NSLog(#"myView : %#", [myView class]);
//[myLabel setText:#"AWAKE"];
[super awakeFromNib];
}
-(void)viewDidLoad {
NSLog(#"viewDidLoad ...");
NSLog(#"myLabel: %#", [myLabel class]);
NSLog(#"myView : %#", [myView class]);
//[myLabel setText:#"VIEW"];
[super viewDidLoad];
}
OUTPUT:
awakeFromNib ...
myLabel: (null)
myView : (null)
viewDidLoad ...
myLabel: UILabel
myLabel: UIImageView
I would be interested to know if this should work, from the docs it looks like it should, but given the way I usually set things up I can't quite understand why it does not in this case.
One more answer :-) It looks like you’re getting this behaviour because the controller loads the views lazily. The view is not loaded immediately, it gets loaded the first time somebody calls the view accessor. Therefore at the time you recieve awakeFromNib the NIB loading process is done, but not for the objects inside your views. See this code:
#property(retain) IBOutlet UILabel *foo;
#synthesize foo;
- (void) awakeFromNib
{
NSLog(#"#1: %i", !!foo);
[super awakeFromNib];
NSLog(#"#2: %i", !!foo);
}
- (void) viewDidLoad
{
NSLog(#"#3: %i", !!foo);
}
This logs:
#1: 0
#2: 0
#3: 1
But if you force-load the view:
- (void) awakeFromNib
{
NSLog(#"#1: %i", !!foo);
[super awakeFromNib];
[self view]; // forces view load
NSLog(#"#2: %i", !!foo);
}
The log changes into this:
#1: 0
#3: 1
#2: 1
I believe your call to super needs to be the first line in the awakeFromNib method, otherwise the elements won't be setup yet.
-(void)awakeFromNib {
[super awakeFromNib];
[imageView setBackgroundColor:[UIColor colorWithRed:0 green:0 blue:0 alpha:1.0]];
[testLabel setText:#"Pants ..."];
}
I know, this post is a bit older, but I recently had a similar problem and would like to share its solution with you.
Having subclassed NSTextView, I wanted to display the row colors in alternating orders. To be able to alter the colors from outside, I added two instance vars to my subclass, XNSStripedTableView:
#interface XNSStripedTableView : NSTableView {
NSColor *pColor; // primary color
NSColor *sColor; // secondary color
}
#property (nonatomic, assign) NSColor *pColor;
#property (nonatomic, assign) NSColor *sColor;
#end
Overwriting highlightSelectionInClipRect: does the trick to set the correct color for the respective clipRect.
- (void)highlightSelectionInClipRect:(NSRect)clipRect
{
float rowHeight = [self rowHeight] + [self intercellSpacing].height;
NSRect visibleRect = [self visibleRect];
NSRect highlightRect;
highlightRect.origin = NSMakePoint(NSMinX(visibleRect), (int)(NSMinY(clipRect)/rowHeight)*rowHeight);
highlightRect.size = NSMakeSize(NSWidth(visibleRect), rowHeight - [self intercellSpacing].height);
while (NSMinY(highlightRect) < NSMaxY(clipRect)) {
NSRect clippedHighlightRect = NSIntersectionRect(highlightRect, clipRect);
int row = (int) ((NSMinY(highlightRect)+rowHeight/2.0)/rowHeight);
NSColor *rowColor = (0 == row % 2) ? sColor : pColor;
[rowColor set];
NSRectFill(clippedHighlightRect);
highlightRect.origin.y += rowHeight;
}
[super highlightSelectionInClipRect: clipRect];
}
The only problem now is, where to set the initial values for pColor and sColor? I tried awakeFromNib:, but this would cause the debugger to come up with an error. So I dug into the problem with NSLog: and found an easy but viable solution: setting the initial values in viewWillDraw:. As the objects are not created calling the method the first time, I had to check for nil.
- (void)viewWillDraw {
if ( pColor == nil )
pColor = [[NSColor colorWithSRGBRed:0.33 green:0.33 blue:0 alpha:1] retain];
if ( sColor == nil )
sColor = [[NSColor colorWithSRGBRed:0.66 green:0.66 blue:0 alpha:1] retain];
}
I do think this solution is quite nice :-) although one could reselect the names of pColor and sColor could be adjusted to be more "human readable".
Are you sure the objects are not nil? NSAssert or NSParameterAssert are your friends:
-(void) awakeFromNib {
NSParameterAssert(imageView);
NSParameterAssert(testLabel);
NSLog(#"awakeFromNib ...");
[imageView setBackgroundColor:[UIColor colorWithRed:0 green:0 blue:0 alpha:1.0]];
[testLabel setText:#"Pants ..."];
[super awakeFromNib];
}
If the objects are really initialized, try to log their address and make sure that the instances that appear in viewDidLoad are the same as those in awakeFromNib:
- (void) awakeFromNib {
NSLog(#"test label #1: %#", testLabel);
}
- (void) viewDidLoad {
NSLog(#"test label #2: %#", testLabel);
}
If the numbers are the same, you can create a category to set a breakpoint on setBackgroundColor and peek in the stack trace to see what’s going on:
#implementation UIImageView (Patch)
- (void) setBackgroundColor: (UIColor*) whatever {
NSLog(#"Set a breakpoint here.");
}
#end
You can do the same trick using a custom subclass:
#interface PeekingView : UIImageView {}
#end
#implementation PeekingView
- (void) setBackgroundColor: (UIColor*) whatever {
NSLog(#"Set a breakpoint here.");
[super setBackgroundColor:whatever];
}
#end
Now you’ll set your UIViewObject to be of class PeekingView in the Interface Builder and you’ll know when anybody tries to set the background. This should catch the case where somebody overwrites the background changes after you initialize the view in awakeFromNib.
But I presume that the problem will be much more simple, ie. imageView is most probably nil.
In case you're using a UIView subclass instead of a UIViewController subclass, you can override loadView method:
- (void)loadView
{
[super loadView];
//IBOutlets are not nil here.
}

Checkbox image toggle in UITableViewCell

I need some guidance on creating a UITableViewCell that has an image on the left which can be toggled. The image should be tappable and act as a toggle (checkbox).
My parts I'm struggling with are:
How do I detect taps on the image and handle those differently to didSelectRowAtIndexPath?
How do I change the image without performing a [tableView reloadData]?
It's actually pretty easy.
Just create a new subclass of UIControl and put it all in there (no need for a separate controller.) Let's call it ToggleImageControl.
#interface ToggleImageControl : UIControl
{
BOOL selected;
UIImageView *imageView;
UIImage *normalImage;
UIImage *selectedImage;
}
Create a ToggleImageControl for each cell, and add it at the appropriate position.
ToggleImageControl *toggleControl = [[ToggleImageControl alloc] initWithFrame: <frame>];
toggleControl.tag = indexPath.row; // for reference in notifications.
[cell.contentView addSubview: toggleControl];
Add a UIImageView to contain the image. Add a target for the touch event.
- (void) viewDidLoad
{
normalImage = [UIImage imageNamed: #"normal.png"];
selectedImage = [UIImage imageNamed: #"selected.png"];
imageView = [[UIImageView alloc] initWithImage: normalImage];
// set imageView frame
[self.view addSubview: imageView];
[self addTarget: self action: #selector(toggleImage) forControlEvents: UIControlEventTouchUpInside];
}
Set the UIImageView's image property to update the image; that will trigger the redraw without side-effects.
- (void) toggleImage
{
selected = !selected;
imageView.image = (selected ? selectedImage : normalImage);
// Use NSNotification or other method to notify data model about state change.
// Notification example:
NSDictionary *dict = [NSDictionary dictionaryWithObject: [NSNumber numberWithInt: self.tag forKey: #"CellCheckToggled"];
[[NSNotificationCenter defaultCenter] postNotificationName: #"CellCheckToggled" object: self userInfo: dict];
}
You will obviously need to massage some stuff. You probably want to pass in the two image names to make it more reusable, and also I'd recommend specifying the notification name string from outside the object as well (assuming you are using the notification method.)
Here's an implementation of the "override touchesBegan:" approach I'm using that is simple and seems to work well.
Just include this class in your project and create and configure a TouchIconTableViewCell instead of a UITableView cell in your tableView:cellForRowAtIndexPath: method.
TouchIconTableViewCell.h:
#import <UIKit/UIKit.h>
#class TouchIconTableViewCell;
#protocol TouchIconTableViewCellDelegate<NSObject>
#required
- (void)tableViewCellIconTouched:(TouchIconTableViewCell *)cell indexPath:(NSIndexPath *)indexPath;
#end
#interface TouchIconTableViewCell : UITableViewCell {
id<TouchIconTableViewCellDelegate> touchIconDelegate; // note: not retained
NSIndexPath *touchIconIndexPath;
}
#property (nonatomic, assign) id<TouchIconTableViewCellDelegate> touchIconDelegate;
#property (nonatomic, retain) NSIndexPath *touchIconIndexPath;
#end
TouchIconTableViewCell.m:
#import "TouchIconTableViewCell.h"
#implementation TouchIconTableViewCell
#synthesize touchIconDelegate;
#synthesize touchIconIndexPath;
- (void)dealloc {
[touchIconIndexPath release];
[super dealloc];
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
CGPoint location = [((UITouch *)[touches anyObject]) locationInView:self];
if (CGRectContainsPoint(self.imageView.frame, location)) {
[self.touchIconDelegate tableViewCellIconTouched:self indexPath:self.touchIconIndexPath];
return;
}
[super touchesBegan:touches withEvent:event];
}
#end
Each time you create or re-use the cell, set the touchIconDelegate and touchIconIndexPath properties. When your icon is touched, the delegate will be invoked. Then you can update the icon or whatever.
So the "..obviously need to massage some stuff.." comment means "...this code doesn't work...".
So
- (void) viewDidLoad
should be
- (id)initWithFrame:(CGRect)frame
{
if ( self = [super initWithFrame: frame] ){
normalImage = [UIImage imageNamed: #"toggleImageNormal.png"];
selectedImage = [UIImage imageNamed: #"toggleImageSelected.png"];
imageView = [[UIImageView alloc] initWithImage: normalImage];
// set imageView frame
[self addSubview: imageView];
[self addTarget: self action: #selector(toggleImage) forControlEvents: UIControlEventTouchDown];
}
return self;
}
As - (void) viewDidLoad never gets called.
It seems that Apple uploaded "TableMultiSelect" as sample codes on iOS Developer Program since 2011-10-12.
Multiple selection in edit mode can be enabled by this code.
self.tableView.allowsMultipleSelectionDuringEditing = YES;
http://developer.apple.com/library/ios/#samplecode/TableMultiSelect/Introduction/Intro.html
Though it can be used only from iOS5.
Several hours I could not find this sample code in Stack Overflow, so I added this info to this post.
There's an even EASIER way to do this, if you override touchesBegan: you need to do an if statement to decide if it's within the check marks proximity, if it's not call [super touchesBegan:touches withEvent:event] and it will act as though it was selected.
I do something similar (starring a favorite) like this, but I think you're demanding a lot from the thumbs of iPhone users with the cell directing people to another view. First of all, I would check out the detail disclosure option on cells. One of the options is a pre-made arrow button that you can attach to. Your call.
You might be able to get away with catching the didSelectRowAtIndexPath event and then doing some other logic instead of redirecting if the touch was on your checkbox, although I don't know how you would get the position. This means you might need to find a way to get ahold of the touch event before it calls didSelectRowAtIndex path, which I'm not quite sure how to do. Have you worked with handling touchesBegan and the like yet?

UIButton.layer.cornerRadius doesn't exist?

I'm implementing a custom UIButton with minimal functionality. The .h file:
#import <Foundation/Foundation.h>
#interface CustomButton : UIButton {
}
#end
I'm encountering a compilation error at line (A) in the .m file:
- (id)initWithCoder:(NSCoder *)coder {
if(self = [super initWithCoder:coder]) {
CALayer *layer = [self layer];
NSLog(#"layer=%#",layer);
NSLog(#"delegate=%#",[layer delegate]);
#ifdef __IPHONE_3_0
layer.cornerRadius = 4.0f; // (A) error: request for member 'cornerRadius' in something not a structure or union
#endif
}
return self;
}
If I comment out line (A), I get the following output:
2009-10-08 17:35:06.681 MyApp[2596:4e07] layer=<CALayer: 0x3cdf520>
2009-10-08 17:35:06.683 MyApp[2596:4e07] delegate=<CustomButton: 0x3cdaff0; baseClass = UIButton; frame = (9 212; 255 55); opaque = NO; autoresize = RM+BM; layer = <CALayer: 0x3cdf520>>
According to the documentation, CALayer should have a cornerRadius property. I'm using iPhone SDK 3.1 and even added an #ifdef to confirm this.
Can someone please show me where I've overlooked the obvious?
Thanks
Make sure you #import <QuartzCore/QuartzCore.h> into your header or implementation file.
Try this,
#import <QuartzCore/QuartzCore.h>
Button.layer.cornerRadius = 15.0;
[Button.layer setMasksToBounds:YES];