I am getting an exception in my iPhone-app,
-[__NSCFString sizeWithAttributes:]: unrecognized selector sent to instance,
when I start my app uner iOS6.1, under iOS7 or higher everything is OK.
The only difference between iOS6 and higher in my project are the XIBs. The error occurs when I press a button.
Maybe it comes from the different XIB, maybe not.
It looks like a memory leak, but i cant figure out why it happens.
The Exception occurrs when is try to calculate the size of a text from a button.
I set Exception-breakpoints to find the error.
Here some infos from the stacktrace:
In this method the error occurs:
- (float) calculateButtonWidth:(TypeButtonRest*) typeButtonRest{
UIFont *font = [UIFont boldSystemFontOfSize:16];
NSDictionary *userAttributes = #{NSFontAttributeName: font,
NSForegroundColorAttributeName: [UIColor blackColor]};
const CGSize textSize = [[typeButtonRest text] sizeWithAttributes: userAttributes];
...
The method is called from here:
- (ButtonMatrixInfos*) calculateButtonSchema:(NSMutableArray*) buttons screenWidth:(double)screenWidth minMargin:(double)minMargin{
ButtonMatrixInfos *returnValue = [[[ButtonMatrixInfos class] alloc] init];
int buttonCount = [buttons count];
[buttons retain];
for (int i=0; i < buttonCount; i++) {
float curWidth = [self calculateButtonWidth:[buttons objectAtIndex:i]];
maxButtonWidth = curWidth > maxButtonWidth ? curWidth : maxButtonWidth;
}
...
My assumption is, that buttons is corrupted. They are coming from here:
-(RadioButtonContainer*)addRadioButtons:(NSMutableArray *)buttons withButtonGroupName:(NSString*) groupName andMarginLeft:(int) marginLeft andMarginRight:(int) marginRight preselected:(NSString*) preselected {
ButtonListLayouter *bll = [[[[ButtonListLayouter class] alloc] init]retain];
ButtonMatrixInfos *bmi = [bll calculateButtonSchema:buttons screenWidth:(screenSize.width - marginLeft - marginRight) minMargin:5];
...
Created here:
NSMutableArray *buttonsRest = [[[NSMutableArray alloc] init]retain];
for (int i=0; i < [buttons count]; i++) {
TypeButtonRest *tpr = [[[[TypeButtonRest class] alloc] init]retain];
tpr.text = [[buttons objectAtIndex:i] objectForKey:#"value"];
tpr.key = [[buttons objectAtIndex:i] objectForKey:#"key"];
[buttonsRest addObject:tpr];
}
I hope this codefragments can help.
best regards
sizeWithAttributes is only available starting at iOS 7.0. You want to use sizeWithFont in iOS 6. Read more here
Related
I am following this example
I have added a button in the view
On selection the button image change to Green icon image.
How could I retain it using this example?
I had updated the existing code of your example to your requirement please find the below url for download the code and review it.
Link : https://www.dropbox.com/s/6xsr4o88khyijun/HorizontalTables.zip?dl=0
Highlight of the code which I had done it.
1) Take the NSMutableArray *arrSelection property in HorizontalTablesAppDelegate class.
2) Fill the data of arrSelection in ArticleListViewController_iPhone class of viewDidLoad method.
for (NSInteger i = 0; i < [self.articleDictionary.allKeys count]; i++)
{
HorizontalTableCell_iPhone *cell = [[HorizontalTableCell_iPhone alloc] initWithFrame:CGRectMake(0, 0, 320, 416) tag:i];
categoryName = [sortedCategories objectAtIndex:i];
currentCategory = [self.articleDictionary objectForKey:categoryName];
cell.articles = [NSArray arrayWithArray:currentCategory];
if(i == 0)
appDelegate.arrSelection = [[NSMutableArray alloc] init];
NSMutableArray *arrSubData = [[NSMutableArray alloc] init];
for(NSInteger j=0; j<currentCategory.count; j++)
[arrSubData addObject:[NSNumber numberWithBool:NO]];
[appDelegate.arrSelection addObject:arrSubData];
[arrSubData release];
[self.reusableCells addObject:cell];
[cell release];
}
3) On HorizontalTableCell_iPhone class of cellForRowAtIndexPath method
NSMutableArray *arrSelectionInfo = appDelegate.arrSelection[tableView.tag];
BOOL isSelect = [arrSelectionInfo[indexPath.row] boolValue];
if(isSelect)
[cell.btnSelection setBackgroundColor:[UIColor greenColor]];
else
[cell.btnSelection setBackgroundColor:[UIColor whiteColor]];
And didSelectRowAtIndexPath method
NSMutableArray *arrUpdate = appDelegate.arrSelection[tableView.tag];
[arrUpdate replaceObjectAtIndex:indexPath.row withObject:[NSNumber numberWithBool:YES]];
[tableView reloadData];
Hope this will work for you.
To keep button state selected you need to store information of selection on a dictionary for the cell. So once cell is reloaded, you can apply selection setting based on information you have.
There is no direct way (even if there was you should now use that, as it will lead to memory abuse) to keep it selected all the time.
I have an app that implements horizontal gallery. In my story board when a job (cell in a tableview) is tapped it will redirect and display job details. In my Job Details Scene : I have index 0 : for company logo and name, salary and the position. in index 1 : i have the horizontal gallery - I created a scrollview programmatically and created a imageviews inside the scrollview.
Here's how I created the scrollview and imageviews:
else if (indexPath.section == 1)
{
[self getImages];
[cell.contentView addSubview:self.scrollView];
return cell;
}
- (void)getImages
{
mutableURLstorage = [[NSMutableArray alloc] init];
imagesArray = [[NSMutableArray alloc]init];
NSInteger noOfImages = (unsigned long)[mutableStorage count];
NSString* strURL;
//store image_paths (company and branch) in a mutable array
for (int i = 0; i < noOfImages; i++)
{
NSDateFormatter *df=[[NSDateFormatter alloc] init];
[df setDateFormat:#"yyyy-MM-dd hh:mm:ss"];
NSDate *date = [NSDate date];
NSDate *oneMinLater = [date dateByAddingTimeInterval:1444];
NSString *hmac_body =[NSString stringWithFormat:#"%#\n%lld\n%#",METHOD,[#(floor([oneMinLater timeIntervalSince1970])) longLongValue],CONTAINER_PATH] ;
// below get different string with shaA diagest
const char *cKey2 = [KEY cStringUsingEncoding:NSASCIIStringEncoding];
const char *cData2 = [hmac_body cStringUsingEncoding:NSASCIIStringEncoding];
unsigned char cHMAC2[CC_SHA1_DIGEST_LENGTH];
CCHmac(kCCHmacAlgSHA1, cKey2, strlen(cKey2), cData2, strlen(cData2), cHMAC2);
NSData *HMAC2 = [[NSData alloc] initWithBytes:cHMAC2 length:sizeof(cHMAC2)];
NSString *HMACStr = [[HMAC2 description] stringByReplacingOccurrencesOfString:#"<" withString:#""];
HMACStr = [HMACStr stringByReplacingOccurrencesOfString:#">" withString:#""];
HMACStr = [HMACStr stringByReplacingOccurrencesOfString:#" " withString:#""];
strURL = [NSString stringWithFormat:#"%#%#?temp_url_sig=%#&temp_url_expires=%lld", URLstorage, CONTAINER_PATH, HMACStr, [#(floor([oneMinLater timeIntervalSince1970])) longLongValue]];
[mutableURLstorage addObject:strURL];
[imagesArray addObject:[[UIImage alloc] initWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:strURL]]]];
}
CGRect screenRect = [[UIScreen mainScreen] bounds];
CGSize pageSize = CGSizeMake(ITEM_WIDTH, self.scrollView.frame.size.height);
_pgCtr = [[UIPageControl alloc] initWithFrame:CGRectMake(0, screenRect.size.height-30, 320, 36)];
_pgCtr.backgroundColor=[UIColor grayColor];
int numberofPage=ceil((float)[imagesArray count]/3.5);
_pgCtr.numberOfPages= numberofPage;
self.scrollView.contentSize = CGSizeMake(320*numberofPage, pageSize.height);
int imgCurrentX = 10;
for (UIImageView* image in imagesArray) {
#autoreleasepool {
imageview = [[UIImageView alloc] initWithFrame:CGRectMake(imgCurrentX, 0, 70, 70)];
imageview.image = (UIImage*)image;
[imageview setUserInteractionEnabled:YES];
[self.scrollView addSubview:imageview];
imgCurrentX = imgCurrentX+80;
}
}
}
I am able to display the horizontal gallery but the images are all for thumbnails.
Now I implemented this code in my viewDidLoad to determine whether an imageview is tapped:
[self.view addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(singleTapAction:)]];
In my singleTapAction method i am using LeveyPopListView to display the enlarged iamges.
- (void)singleTapAction:(UIGestureRecognizer *)singleTap_
{
[self createLeveyPopList];
}
- (void)createLeveyPopList
{
NSString *jobs_name = #"JOBSD";
if(self.lplv.delegate != nil)
return;
self.lplv = [[LeveyPopListView alloc] initWithTitle:#"The following jobs are located here:" options:imagesArray jobName:jobs_name handler:^(NSInteger anIndex) {
}];
self.lplv.delegate = self;
[self.lplv showInView:self.view animated:YES];
}
What I did in my pop up is redisplay the original image gallery (the one in job details scene) but the images are enlarged. My app is successfully implementing the horizontal image gallery. Now my problem is, for example image 2 is tapped, I need to display the image 2 first instead of displaying image 1 first.
I hope someone can help me with this. Thank you!
Add a method to change the size of your ImageView that contains the image, like so:
- (IBAction)buttonTapped:(id)sender {
// Use this Sender property to your advantage
[yourImageViewName setFrame:CGRectMake(0, 0, 100, 100)];
}
Of course, adjust the coordinates to however you would like them. You can also play around in the image view's settings in IB to make sure that your picture does not become distorted upon enlargement.
Now, you could also add tags to your images and enlarge the image view based upon which tag you've pressed. If you want to go that route instead, let me know and I'll post the code. I hope I helped!
Am created UIScrollView programatically and added multiple buttons into that.
Its working well without any prob.
But i need to create another scrollview by copying contents from previous scrollview.
Query:
How to copy First_Scrollview content into Second_Scrollview
Code:
- (void)ScrollviewItems
{
int x = 5;
int y = 5;
for(int i=0; i<totalButtonsCount; i++)
{
CategoryItem = [[UIButton alloc]initWithFrame:CGRectMake(x, y, buttonWidth, 50)];
CategoryItem.titleLabel.backgroundColor = [UIColor clearColor];
CategoryItem.backgroundColor = [UIColor redColor];
[CategoryItem setTitle:[NSString stringWithFormat:#"%d",i]
forState:UIControlStateNormal];
CategoryItem.tag = i;
[CategoryItem addTarget:self
action:#selector(CategoryItemAction:)
forControlEvents:UIControlEventTouchUpInside];
[First_Scrollview addSubview:CategoryItem];
x = x + (buttonWidth + 5);
}
First_Scrollview.contentSize = CGSizeMake(x,50);
Second_Scrollview = [self.Category_Scrollview copy]; // Error
}
Error:
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[UIScrollView copyWithZone:]: unrecognized selector sent to instance
you can do this by this for loop also
for(UIView *v in self.scrollview1.subviews){
[self.scrollview2 addSubview:v];
}
You can't copy views in the way you are trying.
You need to do it as :
NSData * viewData = [NSKeyedArchiver archivedDataWithRootObject:myView];
NSView * viewCopy = [NSKeyedUnarchiver unarchiveObjectWithData:viewData];
Ok so I've written an algorithm here that seems to not work. Basically it draws a list of buttons across multiple pages. It's adapted so that 4 buttons will be drawn per page on iPhone 5, and 3 on iPhone 4S and earlier.
But for some reason, in the 'setFrame' method, I get this error:
Terminating app due to uncaught exception :
'NSInvalidArgumentException', reason: '-[__NSCFArray length]: unrecognized selector sent to instance
The weird thing is that nowhere in the algorithm, or anywhere else in the app does the method length]; get called.
Please also note that I do no when to use this method, and I also know that NSArrays don't have any method length.
Here's the algorithm:
// creates the chapters
+(void)createChapterInScrollView:(UIScrollView *)scrollview withArray:(NSArray *)array withTarget:(id)target andMethod:(SEL)method
{
// sets up some initial variable
int x = 20;
int y = 40;
// fills an array with the y values
int yValues;
NSMutableArray *yContainer = [[NSMutableArray alloc] init];
if (screenHeight == 568) {
yValues = 4;
} else {
yValues = 3;
}
for (yValues = yValues; yValues > 0; yValues = yValues - 1) {
[yContainer addObject:[NSString stringWithFormat:#"%i", y]];
y = y + 70;
}
// creates the buttons using the number of pages
int numOfpages = [self numOfPagesFromArray:array];
int numofPagesLeft = [self numOfPagesFromArray:array];
int numOfButtonsLeft = [array count];
int currentButton = 0;
if (numofPagesLeft == 0) {
} else {
for (numofPagesLeft = numofPagesLeft; numofPagesLeft >= 0; numofPagesLeft = numofPagesLeft - 1) {
for (id object in yContainer) {
if (numOfButtonsLeft > 0) {
UIButton *newButton = [UIButton buttonWithType:UIButtonTypeCustom];
[newButton setTitle:[array objectAtIndex:currentButton] forState:UIControlStateNormal];
[newButton setTitleColor:[UIColor lightGrayColor] forState:UIControlStateHighlighted];
[newButton setFrame:CGRectMake(x, [object floatValue], 280, 50)];
[newButton setTag:(currentButton+1)];
[newButton setContentHorizontalAlignment:UIControlContentHorizontalAlignmentLeft];
[newButton.titleLabel setTextAlignment:NSTextAlignmentLeft];
[newButton addTarget:target action:method forControlEvents:UIControlEventTouchUpInside];
[scrollview addSubview:newButton];
numOfButtonsLeft = numOfButtonsLeft - 1;
currentButton ++;
}
}
x = x + 320;
}
}
// checks if any buttons were actually created
if (numOfpages == 0) {
// tells the user that no content has been downloaded
UILabel *errorLabel = [[UILabel alloc] initWithFrame:CGRectMake(10, 0, 300, 216)];
[errorLabel setBackgroundColor:[UIColor clearColor]];
[errorLabel setTextColor:[UIColor whiteColor]];
[errorLabel setNumberOfLines:10];
[errorLabel setFont:[UIFont systemFontOfSize:17]];
[errorLabel setTextAlignment:NSTextAlignmentCenter];
[errorLabel setText:#"Oops!\n\nLooks like no readable content has been downloaded!\n\nThe content will be automatically downloaded right now!"];
[scrollview addSubview:errorLabel];
}
}
Thanks guys!
In Xcode, go to the Breakpoints navigator, and add exception breakpoint. Simple description how to do it is in this SO answer
Once you have this, you should see exactly which line of code causes the exception.
I use this code to create a UISegment:
//segment controll
NSString *key2 = [allKeys2 objectAtIndex:i];
NSString *obj2 = [DictionaryHomework objectForKey:key2];
int val;
val = [obj2 intValue];
//segment controll
NSArray *itemArray2 = [NSArray arrayWithObjects: #"very easy", #"easy", #"ok", #"hard", #"challenging", nil];
UISegmentedControl *segmentedControl2 = [[UISegmentedControl alloc] initWithItems:itemArray2];
segmentedControl2.frame = CGRectMake(480, -60, 130, 350);
segmentedControl2.segmentedControlStyle = UISegmentedControlStyleBar;
segmentedControl2.selectedSegmentIndex = val - 1;
[segmentedControl2 addTarget:self action:#selector(segmentedControlHomework:) forControlEvents:UIControlEventValueChanged];
segmentedControl2.transform =
CGAffineTransformRotate(segmentedControl2.transform, degreesToRadians(90));
NSArray *arr = [segmentedControl2 subviews];
for (int i = 0; i < [arr count]; i++) {
UIView *v = (UIView*) [arr objectAtIndex:i];
NSArray *subarr = [v subviews];
for (int j = 0; j < [subarr count]; j++) {
if ([[subarr objectAtIndex:j] isKindOfClass:[UILabel class]]) {
UILabel *l = (UILabel*) [subarr objectAtIndex:j];
l.transform = CGAffineTransformMakeRotation(- M_PI / 2.0); //do the reverse of what Ben did
}
}
}
[image1 addSubview:segmentedControl2];
segmentedControl2.tag = i;
[segmentArray addObject: segmentedControl2];
//segment control
On ios5 the control loads the titles in horizontal, while in ios6 in vertical. Why is this? has there been a change in iOS6?
You are fiddling with the inner mechanics of the UISegmentedControl. While you are not technically using private APIs, you are still accessing parts of UIKit that are not publicly documented.
One reason the behavior might have changed in iOS 6 could be that the segmented control now builds its subviews lazily in layoutSubviews ore some other place. It might even not use subviews at all. But I'm just making guesses here. However, it's Apple's choice to change undocumented internals of the framework.
Your code should never have been used in a shipping app. If you want to do something like this (vertical segments?) that the build-in segmented control can't do, build it on your own.