I fell into a strange thing: Why is the following code fragment producting leaks (attrDefault not released)? (assume, 'font' has been defined before and self.text refers to an NSString*):
{
NSStringDrawingContext* context = [[NSStringDrawingContext alloc] init];
NSDictionary* attrDefault = #{ NSForegroundColorAttributeName : [UIColor blackColor],
NSBackgroundColorAttributeName : [UIColor clearColor],
NSFontAttributeName : font,
};
frame.size.height = 1024;
CGRect bounding = [self.text boundingRectWithSize:frame.size
options:NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading|NSStringDrawingUsesDeviceMetrics
attributes:attrDefault context:context];
frame.size.height = bounding.size.height;
[context release];
}
Any idea?
Update:
Surprisingly, if the same code is embedded into an #autoreleasepool statement, the leaks are gone.
#autoreleasepool {
NSStringDrawingContext* context = [[NSStringDrawingContext alloc] init];
NSDictionary* attrDefault = #{ NSForegroundColorAttributeName : [UIColor blackColor],
NSBackgroundColorAttributeName : [UIColor clearColor],
NSFontAttributeName : font,
};
frame.size.height = 1024;
NSString* text = self.text;
CGRect bounding = [text boundingRectWithSize:frame.size
options:NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading|NSStringDrawingUsesDeviceMetrics
attributes:attrDefault context:context];
frame.size.height = bounding.size.height;
[context release]; }
I did not get any leaks with XCode 6, by the way.
This is pretty strange, as I use NSDictionary constructors ( #{....} ) at a lot of locations in my code and the DO NOT produce any leaks.
Anybody with similiar experience?
Related
I want to have a similar functionality as in the Photos app on the iPhone in my Scrollview. So I've added all images to my scrollview like this and it works nicely.
-(void)prepareScrollView
{
for(int i =0;i<[self.layoverPhotoAssets count];i++){
PHAsset *asset = self.layoverPhotoAssets[i];
UIImageView *imageView = [[UIImageView alloc] init];
int x = self.scrollView.frame.size.width * i;
imageView.frame = CGRectMake(x, 0, self.scrollView.frame.size.width, self.scrollView.frame.size.height);
imageView.contentMode = UIViewContentModeScaleAspectFit;
PHImageRequestOptions *options = [[PHImageRequestOptions alloc] init];
options.resizeMode = PHImageRequestOptionsResizeModeFast;
options.deliveryMode = PHImageRequestOptionsDeliveryModeHighQualityFormat; //I only want the highest possible quality
options.synchronous = NO;
options.networkAccessAllowed = YES;
[[PHImageManager defaultManager] requestImageForAsset:asset targetSize:self.scrollView.frame.size contentMode:PHImageContentModeAspectFill options:options resultHandler:^(UIImage *result, NSDictionary *info) {
dispatch_async(dispatch_get_main_queue(), ^{
if(result){
imageView.image = result;
}
});
}];
[self.scrollView setContentSize:CGSizeMake(self.scrollView.frame.size.width * (i + 1), self.scrollView.frame.size.height)];
//self.scrollView.contentSize= ;
[self.scrollView addSubview:imageView];
}
}
However I have 2 questions:
1. Like this, all images will be loaded at once. Memory wise this is quite bad. How can I improve that without worsening the user experience?
2. How can I make the image itself zoomable?
I am using custom font and uppercased text for navigation item title text which contain diacritics. Problem is, the diacritics is cut from top, probably because the title label has wrong height.
So question is, can I affect the title label height? Or access directly the title label and do something like sizeToFit, or change frame or something.
// custom font settings
NSDictionary *attr = #{
NSFontAttributeName: [UIFont fontWithName:#"FishmongerK-XCondLight" size:23.0],
NSForegroundColorAttributeName: [UIColor whiteColor]
};
[[UINavigationBar appearance] setTitleTextAttributes: attr];
// then setting of title
self.navigationItem.title = [NSLocalizedString(#"Oblíbené", nil) uppercaseString];
If i try smaller font size, diacritics is still cut from top.
-(void)setCustomNavTitle:(NSString*)title andDescription:(NSString*)desc {
NSString * locname = [NSString stringWithFormat:#"%#\n", title];
NSString * cityname = [NSString stringWithFormat:#"%#", desc];
NSString * text = [NSString stringWithFormat:#"%#%#", [locname capitalizedString], cityname];
NSDictionary *attribs = #{
NSForegroundColorAttributeName:[UIColor colorWithHexString:#"222222"],
NSFontAttributeName: [UIFont fontWithName:[[Variables getInstance] HelveticaNeue] size:14]
};
NSMutableAttributedString *attributedText = [[NSMutableAttributedString alloc] initWithString:text attributes:attribs];
NSRange range = [text rangeOfString:cityname];
[attributedText setAttributes:#{NSForegroundColorAttributeName:[UIColor colorWithHexString:#"222222"],
NSFontAttributeName:[UIFont fontWithName:[[Variables getInstance] HelveticaNeueLight] size:14]} range:range];
UILabel *titleLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 120, 44)];
titleLabel.font = [UIFont fontWithName:[[Variables getInstance] HelveticaNeueMedium] size:15];
titleLabel.attributedText = attributedText;
titleLabel.backgroundColor = [UIColor clearColor];
titleLabel.textAlignment = NSTextAlignmentCenter;
titleLabel.numberOfLines=0;
titleLabel.lineBreakMode = NSLineBreakByWordWrapping;
titleLabel.textColor = [UIColor blackColor];
self.navigationItem.titleView = titleLabel;
}
i am displaying different items in custom table cell. when i try to display multiline uilabel text. it si only showing single line. even though i calculate the label height
also i try to set new frame with new height after calculation.
my code is as follows:
+(CGRect )getlabelHeight:(CGRect)frame withFontName:(NSString *)font andFontSize:(float)fontSize andText:(NSString *)text
{
CGSize constrainedSize = CGSizeMake(frame.size.width, 9999);
NSDictionary *attributesDictionary = [NSDictionary dictionaryWithObjectsAndKeys:
[UIFont fontWithName:font size:fontSize], NSFontAttributeName,
nil];
NSMutableAttributedString *string = [[NSMutableAttributedString alloc] initWithString:text attributes:attributesDictionary];
CGRect requiredHeight = [string boundingRectWithSize:constrainedSize options:NSStringDrawingUsesLineFragmentOrigin context:nil];
if (requiredHeight.size.width > constrainedSize.width) {
requiredHeight = CGRectMake(0,0, constrainedSize.width, requiredHeight.size.height);
}
CGRect newFrame = frame;
newFrame.size.height = requiredHeight.size.height;
frame = newFrame;
return frame;
}
my tabelview method is as follows:
CGRect descFrame=[Utility getlabelHeight:CGRectMake(65,35+titleFrame.size.height, 250, 20) withFontName:appFont andFontSize:15 andText:[[allComments objectAtIndex:indexPath.row]valueForKey:#"comment"]];
NSLog(#"%# \n %f",[[allComments objectAtIndex:indexPath.row]valueForKey:#"comment"],descFrame.size.height);
[cell.title setFont:[UIFont fontWithName:appFont size:15]];
[cell.title setText:[[allComments objectAtIndex:indexPath.row]valueForKey:#"comment"]];
[cell.title setLineBreakMode:NSLineBreakByWordWrapping];
[cell.title setNumberOfLines:0];
[cell.title setFrame:descFrame];
[cell.title setTextColor:[UIColor blackColor]];
Please help me!!1 i am screwed...
thanks you!!!
NSTextContainer on Mac OS X has a method replaceLayoutManager: to replace the NSLayoutManager of NSTextView with a subclass of NSLayoutManager.
Unfortunately iOS doesn't have such a function.
I tried a combination of these lines of code, but it keeps crashing.
THLayoutManager *layoutManager = [[THLayoutManager alloc] init];
[layoutManager addTextContainer:[self textContainer]];
// [[self textStorage] removeLayoutManager:[self layoutManager]];
//[[self textStorage] addLayoutManager:layoutManager];
[[self textContainer] setLayoutManager:layoutManager];
What is the correct procedure to replace the NSLayoutManager of an UITextview?
Since iOS9, NSTextContainer has the same method as macOS. So now you can replace the layout manager on your storyboard UITextView with your own subclass:
textView.textContainer.replaceLayoutManager(MyLayoutManager())
Have a look at the WWDC2013 Intro To Text Kit video and sample code where they show how to do it.
https://developer.apple.com/downloads/index.action?name=WWDC%202013
https://developer.apple.com/wwdc/videos/
Below is an extract from the code
-(void)viewDidLoad
{
[super viewDidLoad];
// our auto layout views use a design spec that calls for
// 8 pts on each side except the bottom
// since we scroll at the top here, only inset the sides
CGRect newTextViewRect = CGRectInset(self.view.bounds, 8., 0.);
self.textStorage = [[TKDInteractiveTextColoringTextStorage alloc] init];
NSLayoutManager *layoutManager = [[NSLayoutManager alloc] init];
NSTextContainer *container = [[NSTextContainer alloc] initWithSize:CGSizeMake(newTextViewRect.size.width, CGFLOAT_MAX)];
container.widthTracksTextView = YES;
[layoutManager addTextContainer:container];
[_textStorage addLayoutManager:layoutManager];
UITextView *newTextView = [[UITextView alloc] initWithFrame:newTextViewRect textContainer:container];
newTextView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
newTextView.scrollEnabled = YES;
newTextView.keyboardDismissMode = UIScrollViewKeyboardDismissModeOnDrag;
[self.view addSubview:newTextView];
self.textView = newTextView;
self.textStorage.tokens = #{ #"Alice" : #{ NSForegroundColorAttributeName : [UIColor redColor] },
#"Rabbit" : #{ NSForegroundColorAttributeName : [UIColor orangeColor] },
TKDDefaultTokenName : #{ NSForegroundColorAttributeName : [UIColor blackColor] } };
}
The method (sizeWithFont: forWidth: lineBreakMode:) was deprecated in iOS 7.0.
But how can I do a same thing like following code in iOS 7.0?
CGSize fontSize =[self.text sizeWithFont:self.font forWidth:self.frame.size.width lineBreakMode:NSLineBreakByTruncatingTail];
Can (boundingRectWithSize:options:attributes:context:) do this? I am not sure but this is the method I searched on apple document.
Thanks for your assistance.
I have got a category for NSString to get the width or heigth of a string:
- (CGFloat)widthWithFont:(UIFont *)font
{
NSDictionary *attributes = [NSDictionary dictionaryWithObjectsAndKeys:font, NSFontAttributeName, nil];
return [[[NSAttributedString alloc] initWithString:self attributes:attributes] size].width;
}
- (CGFloat)heigthWithWidth:(CGFloat)width andFont:(UIFont *)font
{
NSMutableAttributedString *attrStr = [[NSMutableAttributedString alloc] initWithString:self];
[attrStr addAttribute:NSFontAttributeName value:font range:NSMakeRange(0, [self length])];
CGRect rect = [attrStr boundingRectWithSize:CGSizeMake(width, CGFLOAT_MAX) options:NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading context:nil];
return rect.size.height;
}
For those who want the height with width function but in swift its:
func HeigthWithWidth(stringToSize : String, width : CGFloat, font : UIFont) -> CGFloat {
var attrStr = NSMutableAttributedString(string: stringToSize);
attrStr.addAttribute(NSFontAttributeName, value: font, range: NSRange.init(location: 0, length: stringToSize.characters.count));
var rect = attrStr.boundingRectWithSize(CGSize(width: width, height: CGFloat.max), options: [NSStringDrawingOptions.UsesLineFragmentOrigin, NSStringDrawingOptions.UsesFontLeading], context: nil);
return rect.size.height;
}
Hope that helps those who come looking later