subclassed label class is not key value coding-compliant - objective-c

edit 1
This question is answered here Sorry for the noise.
edit 1
edit 0
I have included more code below and also an image of the result which shows the result I get, which is the same result I got without the subclassing, with just plain labels. In the first 3 rows the labels seem to cover up the button altogether, and in the 4th row there are no labels, and notice that the button #2 is indented on the 4th row. What's going on.
This code only applies to the first of the four rows, but the other 3 rows are similar.
self.cardList = [NSMutableArray arrayWithCapacity:0];
self.yHonorsOrigin = 100;
self.xHonorsOrigin = 100;
self.xHonorsStep = 40.0;
self.xHonorsCurrent = self.xHonorsOrigin;
for( int x=0;x<[cards length]; x++ ){
[cards substringWithRange:NSMakeRange(x,1)];
UIButton *b= [UIButton buttonWithType:UIButtonTypeRoundedRect];
self.xHonorsCurrent += self.xHonorsStep;
[b setTitle:[cards substringWithRange:NSMakeRange(x,1)] forState:UIControlStateNormal];
[b setTitle:#" " forState:UIControlStateDisabled];
[b setFrame:CGRectMake(self.xHonorsCurrent, self.yHonorsOrigin, 20, 20)];
[b setEnabled:YES];
[b setUserInteractionEnabled:YES];
[self.view addSubview:b];
[b addTarget:self action:#selector(spadeButtonPressed:) forControlEvents:UIControlEventTouchUpInside];
self.xHonorsCurrent = self.xHonorsOrigin + self.xHonorsStep/2;
for( int x=0;x<[cards length]-1; x++ ){
self.xHonorsCurrent += self.xHonorsStep;
UILabel *lab = [self valueForKey:#"theSuit" ];
lab.text = #"\u2660";
//lab.tintColor = [UIColor clearColor];
lab.center = CGPointMake(self.xHonorsCurrent, self.yHonorsOrigin);
[self.view addSubview:lab];
}
}
}
edit 0
I have attempted to subclass the UILabel class using BDBoundedLabel, but am throwing an exception that "subclassed label class is not key value coding-compliant for the key theSuit." Please help.
BDBoundedLabel.m
#import "BDBoundedLabel.h"
#implementation BDBoundedLabel
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
}
return self;
}
- (void)drawTextInRect:(CGRect)rect{
CGContextRef context=UIGraphicsGetCurrentContext();
CGContextStrokeRect(context, CGRectInset(self.bounds, 1, 1));
[super drawTextInRect:CGRectInset(rect, 5.0, 5.0)];
}
#end
viewController.h
#import <UIKit/UIKit.h>
#import "BDViewController.h"
#import "BDBoundedLabel.h"
#interface BDnameViewController : UIViewController{
IBOutlet BDBoundedLabel* theSuit;
}
viewController.m
- (void)viewDidLoad
{
[super viewDidLoad];
self.cardList = [NSMutableArray arrayWithCapacity:0];
self.yHonorsOrigin = 100;
self.xHonorsOrigin = 100;
self.xHonorsStep = 40.0;
self.xHonorsCurrent = self.xHonorsOrigin;
// Do any additional setup after loading the view.
self.xHonorsCurrent = self.xHonorsOrigin + self.xHonorsStep/2;
for( int x=0;x<[cards length]-1; x++ ){
self.xHonorsCurrent += self.xHonorsStep;
UILabel *lab = [BDBoundedLabel valueForKey:#"theSuit" ];
lab.text = #"\u2660";
lab.center = CGPointMake(self.xHonorsCurrent, self.yHonorsOrigin);
[self.view addSubview:lab];
}
}

setValue:forKey: and valueForKey: will use the accessors methods (setter and getter), so you need to create them. Declare a property:
#property(nonatomic,assign) BDBoundedLabel* theSuit;
Also, like stated by Benjamin you are calling valueForKey: on a class object, maybe you meant to call the method with self as target, this way:
UILabel *lab = [self valueForKey:#"theSuit" ];
// Equivalent of lab= self.theSuit

Your code does not make any sense. You are performing KVO on a class object, which is almost never done. For most cases, KVO is only ever used on instances of a class, which is not what you are doing here.
Please try and clarify what you are trying to do.

Related

Adding UISearchBar in UINavigationBar with constraints

All,
I want to add UISearchBar to UINavigationbar, I dont dont want to use UISearchController, Just UISearchbar programmatically and it must work in landscape as well.
I tried it is working well in Portrait well, but in Landscape, i have issues in iPhone X width. Can we use Constraints.
Below is the code
CGFloat width = [UIScreen mainScreen].bounds.size.width;
search = [[UISearchBar alloc] initWithFrame:CGRectMake(0, 0, width - 2 * 44 - 2 * 15, 44)];
search.delegate = self; // search.tintColor = [UIColor redColor];
search.searchBarStyle = UISearchBarStyleMinimal;
search.placeholder = #"Search";
search.translucent = NO;
search.opaque = NO;
search.showsCancelButton = NO;
[search setBackgroundImage:[[UIImage alloc] init]];
//customize textfield inside UISearchBar
#try {
for (id object in [[[search subviews] firstObject] subviews])
{
if (object && [object isKindOfClass:[UITextField class]])
{
UITextField *textFieldObject = (UITextField *)object;
textFieldObject.backgroundColor = [UIColor whiteColor];
textFieldObject.borderStyle = UITextBorderStyleRoundedRect;
textFieldObject.layer.borderColor = (__bridge CGColorRef _Nullable)([brandingObj getValueForKey:navBarTitleColor]);
textFieldObject.layer.borderWidth = 1.0;
break;
}
}
}
#catch (NSException *exception) {
NSLog(#"Error while customizing UISearchBar");
}
#finally {
}
I don't understand why you want to use UISearchDisplayController, its highly configurable and recommended by apple, working with geometry (CGRecr, CGFrame, etc.) to adjust UIKit objects layout could be a pain, use auto layout avoiding UIKits convenience initializers, to adjust later constraints.
Anyway if you want explicitly do with this way, this should work.
#import "ViewController.h"
#interface ViewController ()<UISearchBarDelegate>
#property UISearchBar *searchbar;
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
_searchbar = [UISearchBar new];
_searchbar.delegate = self;
_searchbar.searchBarStyle = UISearchBarStyleMinimal;
self.navigationItem.titleView = self.searchbar;
// Do any additional setup after loading the view, typically from a nib.
}
Maybe you should need configure appearance , take a look here
Cheers.

why is - (null) at the end of my object

I have the following class
#import <UIKit/UIKit.h>
#interface UIImageViewInfo : UIImageView
#property(nonatomic,strong) NSString* colorInfo;
#end
when creating an UIImageViewInfo in function1(post below) I get the correct result
"UIImageViewInfo: 0x1d8acd60; baseClass = UIImageView; frame = (0 0;
20 20); opaque = NO; userInteractionEnabled = NO; tag = 2000; layer =
CALayer: 0x1d8a0560>>"
but creating the something in function2(posted below) I get the -(null)
UIImageViewInfo: 0x8372c40; baseClass = UIImageView; frame = (0 0; 20
20); alpha = 0; hidden = YES; opaque = NO; userInteractionEnabled =
NO; tag = 2000; layer = CALayer: 0x8380090>> - (null)
Why is there a - (null) ??
Thanx in advance
P.S> here is more from my code
-(void)function1{
UIImageViewInfo *image;
self.solutionPinSlots = [[NSMutableArray alloc] init];
for (int i=0; i<M; i++) {
image = [[UIImageViewInfo alloc] initWithImage:[UIImage imageNamed:#"solutionPeg#2x.png"]];
image.translatesAutoresizingMaskIntoConstraints=NO;
image.hidden=YES;
image.alpha = 0;
image.colorInfo = #"clear";
image.tag = 2000*(self.brainController.slotsIndex+1) +i;
[self.solutionPinSlots addObject:image];
[self.view addSubview:(UIImageViewInfo *)self.solutionPinSlots[i]];
}
NSLog(#"solutionSlots: %#",self.solutionPinSlots);
__block int counter = 0;
[self.brainController.solution enumerateObjectsUsingBlock:^(NSString *peg, NSUInteger idx, BOOL *stop){
for (int i=0;i<M;i++) {
if ([self.brainController.slots[self.brainController.slotsIndex][i] isEqual:peg]) {
if (i==idx) {
((UIImageViewInfo *) self.solutionPinSlots[counter]).backgroundColor = [UIColor whiteColor];
((UIImageViewInfo *) self.solutionPinSlots[counter]).colorInfo=#"white";
}else{
((UIImageViewInfo *) self.solutionPinSlots[counter]).backgroundColor = [UIColor blackColor];
((UIImageViewInfo *) self.solutionPinSlots[counter]).colorInfo=#"black";}
((UIImageViewInfo *) self.solutionPinSlots[counter]).hidden=NO;
((UIImageViewInfo *) self.solutionPinSlots[counter++]).alpha=1;
}
}
}];
[self.solutionPinSlots shuffle];
[self updateSolutionPinSlots];
}
-(void)function2{
NSString *obj;
for (int idx=0; idx< M;idx++ ) {
UIImageViewInfo *image = [[UIImageViewInfo alloc] initWithImage:[UIImage imageNamed:#"solutionPeg#2x.png"]];
image.translatesAutoresizingMaskIntoConstraints=NO;
obj = (NSString *) [self.solutionPinSlots objectAtIndex:idx];
image.tag=2000*(self.brainController.slotsIndex+1)+idx;
image.hidden=NO;
image.alpha = 1;
if ([obj isEqualToString:#"clear"]) {
image.hidden=YES;
image.alpha = 0;
image.colorInfo=#"clear";
image.backgroundColor=[UIColor clearColor];
}else if ([obj isEqualToString:#"white"]){
image.colorInfo=#"white";
image.backgroundColor=[UIColor whiteColor];
}else if ([obj isEqualToString:#"black"]){
image.colorInfo=#"black";
image.backgroundColor=[UIColor blackColor];
}else{
NSLog(#"Something is Wrong!!!");
}
[self.solutionPinSlots replaceObjectAtIndex:idx withObject:image];
[self.view addSubview:image];
}
}
Never mind. It is coming from the description method of UIView, which is rather complex and dumps a bunch of information about the view. One of the conditionals is being tripped up by your configuration and causing the (null) at the end.
Safe to ignore.
There is no UIImageViewInfo class in UIKit, so the implementation must be in your project. In that implementation, there is likely a description method that is implemented something like:
- (NSString*)description {
....
return [NSString stringWithFormat:#"UIImageViewInfo:%p; %# - %#", self, [super description], someInstanceVariableThatHappensToBeNil]];
}
Only your description is likely more complex due to the sometimes does this sometimes that output.
Not that you should not prefix classes with UI when subclassing the UIKit.
It is because your NSLog call (which you do not show) is asking for a second object, and that second object is null.

UIPageControl doesn't properly react to taps

In my TestApp, I created a class "Carousel" which should let me create a swipe menu with a UIPageControl in an easy way (by simply creating an instance of the class Carousel).
Carousel is a subclass of UIView
At init, it creates an UIView, containing UIScrollView, UIPageControl
I can add further UIViews to the scroll view
I don't know if this is the proper way to do it, but my example worked quite well in my TestApp. Swiping between pages works perfectly and the display of the current page in the UIPageControl is correct.
If there were not one single problem: The UIPageControl sometimes reacts to clicks/taps (I only tested in Simulator so far!), sometimes it doesn't. Let's say most of the time it doesn't. I couldn't find out yet when it does, for me it's just random...
As you can see below, I added
[pageControl addTarget:self action:#selector(pageChange:) forControlEvents:UIControlEventValueChanged];
to my code. I thought this would do the proper handling of taps? But unfortunately, pageChange doesn't get always called (so the value of the UIPageControl doesn't change every time I click).
I would appreciate any input on this because I couldn't find any solution on this yet.
This is what I have so far:
Carousel.h
#import <UIKit/UIKit.h>
#interface Carousel : UIView {
UIScrollView *scrollView;
UIPageControl *pageControl;
BOOL pageControlBeingUsed;
}
- (void)addView:(UIView *)view;
- (void)setTotalPages:(NSUInteger)pages;
- (void)setCurrentPage:(NSUInteger)current;
- (void)createPageControlAt:(CGRect)cg;
- (void)createScrollViewAt:(CGRect)cg;
#end
Carousel.m
#import "Carousel.h"
#implementation Carousel
- (id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
// Create a scroll view
scrollView = [[UIScrollView alloc] init];
[self addSubview:scrollView];
scrollView.delegate = (id) self;
// Init Page Control
pageControl = [[UIPageControl alloc] init];
[pageControl addTarget:self action:#selector(pageChange:) forControlEvents:UIControlEventValueChanged];
[self addSubview:pageControl];
}
return self;
}
- (IBAction)pageChange:(id)sender {
CGRect frame = scrollView.frame;
frame.origin.x = frame.size.width * pageControl.currentPage;
frame.origin.y = 0;
[scrollView scrollRectToVisible:frame animated:TRUE];
NSLog(#"%i", pageControl.currentPage);
}
- (void)addView:(UIView *)view {
[scrollView addSubview:view];
}
- (void)createPageControlAt:(CGRect)cg {
pageControl.frame = cg;
}
- (void)setTotalPages:(NSUInteger)pages {
pageControl.numberOfPages = pages;
}
- (void)setCurrentPage:(NSUInteger)current {
pageControl.currentPage = current;
}
- (void)createScrollViewAt:(CGRect)cg {
[scrollView setPagingEnabled:TRUE];
scrollView.frame = cg;
scrollView.contentSize = CGSizeMake(scrollView.frame.size.width*pageControl.numberOfPages, scrollView.frame.size.height);
[scrollView setShowsHorizontalScrollIndicator:FALSE];
[scrollView setShowsVerticalScrollIndicator:FALSE];
}
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
float frac = scrollView.contentOffset.x / scrollView.frame.size.width;
NSUInteger page = lround(frac);
pageControl.currentPage = page;
}
#end
ViewController.m (somewhere in viewDidLoad)
Carousel *carousel = [[Carousel alloc] initWithFrame:CGRectMake(0, 0, 320, 460)];
for (int i=0; i<5; i++) {
UIView *view = [[UIView alloc] initWithFrame:CGRectMake(i * 320, 0, 320, 420)];
UIColor *color;
if(i%3==0) color = [UIColor blueColor];
else if(i%3==1) color = [UIColor redColor];
else color = [UIColor purpleColor];
view.backgroundColor = color;
[carousel addView:view];
view = nil;
}
[carousel setTotalPages:5];
[carousel setCurrentPage:0];
[carousel createPageControlAt:CGRectMake(0,420,320,40)];
[carousel createScrollViewAt:CGRectMake(0,0,320,420)];
Your code is correct. Most likely the frame of your pageControl is pretty small, so theres not a lot of area to look for touch events. You would need to increase the size of the height of pageControl in order to make sure taps are recognized all of the time.

Accessing NSMutableArray Difficulties

I am trying to build an NSMutableArray each time a button is pressed. I am using NSLog to check the array count after each button pressed and the value is zero. THe code is below.
ProjectViewController.h
NSMutableArray *numberQuery
...
#property (nonatomic, retain) NSMutableArray *numberQuery;
ProjectViewController.m
- (void)makeButtons{
UIButton * pickButton;
int y_plot = 150;
int x_plot = 70;
int z = 0;
for(int y = 1; y < 10; y++)
{
for(int x = 1; x < 5; x++){
z++;
pickButton = [UIButton buttonWithType:UIButtonTypeCustom];
pickButton.frame = CGRectMake(x*x_plot, y_plot, 60, 40);
[pickButton setBackgroundImage:[UIImage imageNamed:#"btnUnselected.png"] forState:UIControlStateNormal];
[pickButton addTarget:self action:#selector(digitClick:) forControlEvents:UIControlEventTouchUpInside];
[pickButton setTitle:[NSString stringWithFormat:#"%d",z] forState:UIControlStateNormal];
pickButton.titleLabel.textColor = [UIColor blackColor];
pickButton.tag = z;
[self.view addSubview:aButton];
}
y_plot=y_plot+45;
}
}
//************************
- (void)digitClick:(id)sender{
UIButton * chosenButton =(UIButton *)sender;
if ([sender isSelected] ==FALSE) {
[sender setSelected:TRUE];
[chosenButton setBackgroundImage:[UIImage imageNamed:#"btnSelected.png"] forState:UIControlStateNormal];
chosenButton.titleLabel.textColor = [UIColor whiteColor];
if([queryNumbersX count]<6){
[self numberSearchArray:chosenButton.tag];
}
}
else
{[sender setSelected:FALSE];
[chosenButton setBackgroundImage:[UIImage imageNamed:#"btnUnselected.png"]forState:UIControlStateNormal];
chosenButton.titleLabel.textColor = [UIColor blackColor];
}
forState:UIControlStateNormal];
NSLog(#"clicked button with title %d",chosenButton.tag);
}
//************************
-(void) numberSearchArray:(NSInteger)newNumber;
{
[self.numberQuery addObject:[NSNumber numberWithInt: newNumber]];
NSLog(#"numberSearchArray %d - count %d",newNumber, [self.numberQuery count]);
}
Am I using the NSMutableArray in the right manner...declaration?
This is the code in the viewDidLoad method
NSMutableArray *numberQuery = [[NSMutableArray alloc] initWithObjects:nil];
Although I have the array declared int he header file, It seems as though I cannot access it outside of the method in which it was allocated.
#property (nonatomic, retain) NSMutableArray *numberQuery;
You must balance that with
#synthesize numberQuery;
in the .m
and the correct creation would be
self.numberQuery = [NSMuatableArray arrayWithCapacity:someNumber];
By doing this
NSMutableArray *numberQuery = [[NSMutableArray alloc] initWithObjects:nil];
You are not using your #property you are creating a new variable, this is why you get the warning that your variable is not use, because it's scope is actually just the viewDidLoad method instead of the object.
It looks like that you have never alloced numberQuery. So it is always nil and thus addObject method is ignored. You need to alloc this in init (or any suitable place you like) and release in dealloc (or in other suitable place).

UIScrollView only works if the child views aren't hit

I have a scroll view that doesn't scroll right, I've simplified the code for below.
It draws the view and some horizontal buttons that i add more stuff to in the real code.
If you drag the whitespace between the buttons the view scrolls. If you happen to put your finger on a button, it won't scroll.
After a related suggestion, I tried to add the delaysContentTouches = YES line, but it doesn't seem to make a difference.
UIScrollview with UIButtons - how to recreate springboard?
What am I doing wrong?
TIA,
Rob
Updated the code
- (void)viewDidLoad {
l = [self landscapeView];
[self.view addSubview:l];
[l release];
}
- (UIScrollView *) landscapeView {
// LANDSCAPE VIEW
UIScrollView *landscapeView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, 320, 325)];
landscapeView.backgroundColor = [UIColor whiteColor];
landscapeView.delaysContentTouches = YES;
NSInteger iMargin, runningY, n;
iMargin = 3;
runningY = iMargin;
for (n = 1; n <= 38; n++) {
//add day labels
UIButton *templabel = [[UIButton alloc] initWithFrame:CGRectMake(iMargin,runningY,320 - ( 2 * iMargin),20)];
templabel.backgroundColor = [UIColor grayColor];
[landscapeView addSubview:templabel];
[templabel release];
runningY = runningY + 30;
}
landscapeView.contentSize = CGSizeMake( 320, runningY);
return landscapeView;
}
I can't duplicate your results; when I create a scrollView and add buttons, scrolling is still active even when doing a touch-down on the button. Are you setting any other UIScrollView properties, or subclassing any methods, that aren't showing up in your simplified code?
It looks like one thing that's going on is that the getter for landScapeView is a complicated constructor...so every time you do [self landscapeView] or self.landscapeView, you're creating a whole new UIScrollView and operating on that.
I'd try something like this in your .h file:
#interface MyClass: MyParent {
UIScrollView *landscapeView;
}
#property (retain) UIScrollView *landscapeView;
...and this in your .m file:
#implementation MyClass
#synthesize landscapeView;
(void)viewDidLoad
{ l = [[[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, 320, 325)] autorelease];
[self.view addSubview:self.landscapeView]; [l release];
landscapeView.backgroundColor = [UIColor whiteColor];
landscapeView.delaysContentTouches = YES;
NSInteger iMargin, runningY, n;
iMargin = 3;
runningY = iMargin;
for (n = 1; n <= 38; n++) { //add day labels
UIButton *templabel = [[UIButton alloc] initWithFrame:CGRectMake(iMargin,runningY,320 - ( 2 * iMargin),20)];
templabel.backgroundColor = [UIColor grayColor];
[landscapeView addSubview:templabel];
[templabel release]; runningY = runningY + 30;
}
landscapeView.contentSize = CGSizeMake( 320, runningY);
}