I just updated my app because of a warning and now I get the following error
Implicit conversion from enumeration type 'enum UIViewAnimationCurve' to different enumeration type 'UIAnimationOptions' (aka 'enum UIViewAnimationOptions')
This is the code I use.
[UIView animateWithDuration:1 delay:0 options:UIViewAnimationCurveEaseIn animations:^{arrow2.titleLabel.alpha = 1,arrow2.center = CGPointMake(160, 120); ball.center = CGPointMake(160, 120);text.alpha = 0;} completion:^ (BOOL completed) {} ];
what do I need to do to get rid of this warning/
Thanks
Found the answer added Option to code UIViewAnamation*Option*CurveEaseIn took care of it.
Related
I am getting this error "Incompatible block pointer types sending 'void (^)(void)' to parameter of type 'void (^ _Nonnull)(NSTimer * _Nonnull __strong)'" in this line "[NSTimer scheduledTimerWithTimeInterval:3/self.MAX repeats:YES block:^{".
Thanks in advance.
self.progressTimer = [NSTimer scheduledTimerWithTimeInterval:3/self.MAX repeats:YES block:^{
self.progressRight.constant = self.progressRight.constant + 1.0;
if (self.progressRight.constant >= self.MAX) {
self.ENOUGH = YES;
self.PANIC = NO;
[self.progressTimer invalidate];
[self submit];
}
}];
The block signature is wrong.
To fix this kind of issue yourself
Comment out the entire method.
Retype the first characters and use code completion.
Select the desired method.
The compiler will suggest
[NSTimer scheduledTimerWithTimeInterval:3/self.MAX repeats:YES block:^(NSTimer * _Nonnull timer) {
// code
}];
That's what the error message says:
Expected type (^ _Nonnull)(NSTimer * _Nonnull __strong)
Given type 'void (^)(void)
I am capturing a method-scoped object in a C block and I want to avoid retain cycles. Here is my code: (balloon is a custom view created within my current method)
balloon.onAddedToViewHierarchy = ^{
CGRect globalRect = [[UIApplication sharedApplication].keyWindow convertRect:self.frame fromView:self.superview];
CGRect targetFrame = CGRectMake(20, 0, SCREEN_WIDTH - 40, 60);
targetFrame.origin.y = below ? globalRect.origin.y + globalRect.size.height + 10 : globalRect.origin.y - 10 - 60/*height*/;
balloon.frame = globalRect;//targetFrame;
};
at the last line (balloon.frame = globalRect;) I am told that capturing balloon in block will lead to a retain cycle. I know about ARC, ownerships, retain counts etc and I know the reason. I am just looking for a way to implicitly get rid of retaining balloon (it's already guaranteed to be retained by being referenced from other places) and using a __weak pointer, or __block if appropriate. I know I can do this:
__weak UIView *weakBalloon = balloon;
balloon.onAddedToViewHierarchy = ^{
CGRect globalRect = [[UIApplication sharedApplication].keyWindow convertRect:self.frame fromView:self.superview];
CGRect targetFrame = CGRectMake(20, 0, SCREEN_WIDTH - 40, 60);
targetFrame.origin.y = below ? globalRect.origin.y + globalRect.size.height + 10 : globalRect.origin.y - 10 - 60/*height*/;
weakBalloon.frame = globalRect;//targetFrame;
};
But actually I'm exploring ways to implement the same behavior without explicitly creating a new pointer. I am looking for something like this: (it won't compile, just a demo)
balloon.onAddedToViewHierarchy = ^{
CGRect globalRect = [[UIApplication sharedApplication].keyWindow convertRect:self.frame fromView:self.superview];
CGRect targetFrame = CGRectMake(20, 0, SCREEN_WIDTH - 40, 60);
targetFrame.origin.y = below ? globalRect.origin.y + globalRect.size.height + 10 : globalRect.origin.y - 10 - 60/*height*/;
((__weak UIView*)balloon).frame = globalRect;//targetFrame;
};
Is something similar possible? I know there's nothing wrong with declaring a __weak variable, it will just work perfectly. I'm just curious that if such an implicit behavior is possible or not.
Consider using the #weakify and #strongify macros, included in Reactive Cocoa or the Extended Objective-C Library.
For demonstration of this, see the Avoiding Retain Cycles discussion in Ray Wenderlich's
part 2 of 2 discussion about Reactive Cocoa.
That article provides the following example:
__weak RWSearchFormViewController *bself = self; // Capture the weak reference
[[self.searchText.rac_textSignal map:^id(NSString *text) {
return [self isValidSearchText:text] ? [UIColor whiteColor] : [UIColor yellowColor];
}]
subscribeNext:^(UIColor *color) {
bself.searchText.backgroundColor = color;
}];
Which they go on to suggest could be replaced with:
#weakify(self)
[[self.searchText.rac_textSignal map:^id(NSString *text) {
return [self isValidSearchText:text] ? [UIColor whiteColor] : [UIColor yellowColor];
}]
subscribeNext:^(UIColor *color) {
#strongify(self)
self.searchText.backgroundColor = color;
}];
I have a method that gives me the perfect size for a UITextView given a length of string (with the corresponding correct font size) :
- (NSInteger) heightOfLabel:(NSString*) string {
CGSize maximumLabelSize = CGSizeMake([[UIScreen mainScreen] bounds].size.width - 40, FLT_MAX);
CGSize expectedLabelSize = [[NSString stringTrimmedForLeadingAndTrailingWhiteSpacesFromString:string]
sizeWithFont:[UIFont systemFontOfSize:15]
constrainedToSize:maximumLabelSize
lineBreakMode:NSLineBreakByWordWrapping];
return expectedLabelSize.height + 5;
}
In fact, it still gives me a perfect fit, even in iOS7. Although now it comes up with a warning method that says I shouldn't use 'sizeWithFont:contrainedToSize:lineBreakMode'.
It now says I should be using -boundingRectWithSize:options:attributes:context:
This method isn't new to iOS7 and therefore i figure that it is okay to ask it on stack overflow, rather than going across to the official apple developers forum.
I have three questions:
1) Because it is deprecated, does that mean I should definitely replace it, despite it still working?
2) I have tried many different boundingRectWithSize: methods, with various variables but it is never perfect, it always seems to be slightly out (as many stackoverflow questions point out) - is there a perfect replacement with this none-deprecated method that does exactly the same as my previous method with as minimal hassle?
3) why remove this method? Is it because of the overlap with this other method?
After an hour of trial error I managed to make it work:
CGSize maximumLabelSize = CGSizeMake(tableView.width, MAXFLOAT);
NSStringDrawingOptions options = NSStringDrawingTruncatesLastVisibleLine |
NSStringDrawingUsesLineFragmentOrigin;
NSDictionary *attr = #{NSFontAttributeName: [UIFont systemFontOfSize:15]};
CGRect labelBounds = [string boundingRectWithSize:maximumLabelSize
options:options
attributes:attr
context:nil];
Update:
As Mr. T mentions in answer below : In iOS 7 and later, this method returns fractional sizes (in the size component of the returned CGRect); to use a returned size to size views, you must use raise its value to the nearest higher integer using the ceil function. ceilf function is recommended to use.
CGFloat height = ceilf(labelBounds.size.height);
I believe the function was deprecated because that series of NSString+UIKit functions were based on the UIStringDrawing library, which wasn't thread safe. If you tried to run them not on the main thread (like any other UIKit functionality), you'll get unpredictable behaviors. In particular, if you ran the function on multiple threads simultaneously, it'll probably crash your app. This is why in iOS 6, they introduced a the boundingRectWithSize:... method for NSAttributedStrings. This was built on top of the NSStringDrawing libraries and is thread safe.
If you look at the new NSString boundingRectWithSize:... function, it asks for an attributes array in the same manner as a NSAttributeString. If I had to guess, this new NSString function in iOS 7 is merely a wrapper for the NSAttributeString function from iOS 6.
On that note, if you were only supporting iOS 6 and iOS 7, then I would definitely change all of your NSString's sizeWithFont:... to the NSAttributeString's boundingRectWithSize. It'll save you a lot of headache if you happen to have a weird multi-threading corner case! Here's how I converted NSString's sizeWithFont:constrainedToSize::
What used to be:
NSString *text = ...;
CGFloat width = ...;
UIFont *font = ...;
CGSize size = [text sizeWithFont:font
constrainedToSize:CGSizeMake(width, CGFLOAT_MAX)];
Can be replaced with:
NSString *text = ...;
CGFloat width = ...;
UIFont *font = ...;
NSAttributedString *attributedText =
[[NSAttributedString alloc]
initWithString:text
attributes:#
{
NSFontAttributeName: font
}];
CGRect rect = [attributedText boundingRectWithSize:CGSizeMake(width, CGFLOAT_MAX)
options:NSStringDrawingUsesLineFragmentOrigin
context:nil];
CGSize size = rect.size;
Please note the documentation mentions:
In iOS 7 and later, this method returns fractional sizes (in the size
component of the returned CGRect); to use a returned size to size
views, you must use raise its value to the nearest higher integer
using the ceil function.
So to pull out the calculated height or width to be used for sizing views, I would use:
CGFloat height = ceilf(size.height);
CGFloat width = ceilf(size.width);
For linebreak issue:
- (CGFloat)heightNeededForText:(NSString *)text withFont:(UIFont *)font width:(CGFloat)width lineBreakMode:(NSLineBreakMode)lineBreakMode {
NSMutableParagraphStyle * paragraphStyle = [[NSMutableParagraphStyle alloc] init];
paragraphStyle.lineBreakMode = lineBreakMode;
CGSize size = [text boundingRectWithSize:CGSizeMake(width, CGFLOAT_MAX)
options:(NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading)
attributes:#{ NSFontAttributeName: font, NSParagraphStyleAttributeName: paragraphStyle }
context:nil].size;
return ceilf(size.height);
}
Swift version of the Alexander of Norway's answer...
func heightNeededForText(text: NSString, withFont font: UIFont, width: CGFloat, lineBreakMode:NSLineBreakMode) -> CGFloat {
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.lineBreakMode = lineBreakMode
let size: CGSize = text.boundingRectWithSize(CGSizeMake(width, CGFloat.max), options: [.UsesLineFragmentOrigin, .UsesFontLeading], attributes: [ NSFontAttributeName: font, NSParagraphStyleAttributeName: paragraphStyle], context: nil).size//text boundingRectWithSize:CGSizeMake(width, CGFLOAT_MA
return ceil(size.height);
}
In the code where you want to get the height just call the method like below...
let size = self.heightNeededForText(text as NSString, withFont: UIFont.systemFontOfSize(15.0), width: scrollView.frame.size.width - 20, lineBreakMode: NSLineBreakMode.ByWordWrapping) //Can edit the font size and LinebreakMode
I'm getting this warning
Implicit conversion from enumeration type 'UIViewAnimationCurve' to different enumeration type 'UIViewAnimationTransition'
from the last line in this code
if (((UIView*)[[slideViews subviews] objectAtIndex:0]).frame.origin.x > SLIDE_VIEWS_MINUS_X_POSITION) {
UIView* tempRight2View =[[slideViews subviews] objectAtIndex:[[slideViews subviews] count]-1];
[UIView beginAnimations:#"ALIGN_TO_MINIMENU" context:NULL];
[UIView setAnimationTransition:UIViewAnimationCurveEaseInOut forView:viewAtLeft cache:YES];
I'm adapting code from StackScrollView, any know how to "explicitly" convert?
TIA
you are using a different set of enum: there you must put one of the UIViewAnimationTransition
typedef enum {
UIViewAnimationTransitionNone,
UIViewAnimationTransitionFlipFromLeft,
UIViewAnimationTransitionFlipFromRight,
UIViewAnimationTransitionCurlUp,
UIViewAnimationTransitionCurlDown} UIViewAnimationTransition;
while you are using one of UIViewAnimationCurve:
typedef enum {
UIViewAnimationCurveEaseInOut,
UIViewAnimationCurveEaseIn,
UIViewAnimationCurveEaseOut,
UIViewAnimationCurveLinear} UIViewAnimationCurve
they are still all integer but from different groups of constants
All enums are integers.
The method your calling takes a UIViewAnimationTransition.
+ (void)setAnimationTransition:(UIViewAnimationTransition)transition
forView:(UIView *)view
cache:(BOOL)cache;
you're setting it to one of the values defined by UIViewAnimationCurve.
My code:
CGPoint *tp_1 = CGPointMake(160, 240);
gives an "Incompatible types in initialization" error... why is this??
CGPointMake returns a struct, not a pointer to a struct. So the correct code is:
CGPoint tp_1 = CGPointMake(160, 240);
Looks like CGPointMake isn't returning a pointer.