I'm trying to learn how to use UIViewPropertyAnimator in objc. I made a simple test app with an object called 'blueBox'. I want to vary the properties of blueBox.
I declare 'animator' outside of #implementation ... #end:
UIViewPropertyAnimator *animator;
then define it like so:
- (void)viewDidLoad {
[super viewDidLoad];
CGRect newFrame = CGRectMake(150.0, 350.0, 100.0, 150.0);
animator = [[UIViewPropertyAnimator alloc]
initWithDuration:2.0
curve:UIViewAnimationCurveLinear
animations:^(void){
self.blueBox.frame = newFrame;
self.blueBox.backgroundColor = [UIColor redColor];
}];
}
When I want to use it I write:
animator.startAnimation;
It works as expected (changes the object's color and frame) but there is a warning on 'animator.startAnimation;' that says "Property access result unused - getters should not be used for side effects". What property access result is that referring to? How should I write that so I don't get a warning?
startAnimation is a method, not a property. You should write:
[animator startAnimation];
Though Objective-C does allow you to use property syntax when calling a method that takes no parameters, your use is written like you are attempting to read a property value. But since (obviously) you make no attempt to store the result (there isn't one), the compiler complains you are ignoring the accessed value.
Simply avoid the wrong syntax and you avoid the issue.
BTW, you claim that the line:
UIViewPropertyAnimator *animator;
is outside the #implementation / #end pair. That makes it a file global variable. Is that what you really want? If you want it to be an instance variable of the class (which is probably what you really want), it should be:
#implementation YourClass {
UIViewPropertyAnimator *animator; //instance variable
}
// your methods
#end
Related
Good morning, I am looking through some old code online in objective c and I am having trouble finding out what the following means.
The class is subclassing UIView and is following the UIScrollViewDelegate protocol. The following is the class method I have some questions about:
#property(nonatomic, strong) NSDate * _Nonnull date;
- (void)layoutSubviews {
[super layoutSubviews];
if(!self.pagingView) {
UIScrollView *pagingView = [[UIScrollView alloc] initWithFrame:self.bounds];
pagingView.pagingEnabled = YES;
pagingView.directionalLockEnabled = YES;
pagingView.delegate = self;
[pagingView setAutoresizingMask:UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight];
[self addSubview:pagingView];
self.pagingView = pagingView;
}
CGRect f = self.pagingView.bounds;
CGSize s = self.pagingView.contentSize;
if(s.width != f.size.width * 3) {
self.date = self.date;
}
}
First, I am not sure what the [super layoutSubviews] is achiving and I am not sure what the self.date = self.date is trying to do. Is it only setting itself with itself? If so, I am not able to get this to work with swift. (Which I am trying to convert the code to)
https://github.com/Daij-Djan/DDCalendarView/blob/master/DDCalendarView_objc/DDCalendarView.m
Thanks again for any help;
In Objective-C, dot notation is a shorthand (syntactic sugar) for property accessor method calls. What you've posted could be rewritten as:
if width != size.width * 3 {
[self setDate:[self date]];
}
In other words, the current value of the date property is being passed back into the date property setter. In typical code, this won't really do anything. Without seeing the implementation of the date setter (and/or getter) method, it's impossible to say why the code you're looking at is doing this. However, my guess is that the date setter has a side-effect that is triggered anytime it's called, so this is a convenient way to trigger that side-effect without changing the property's value.
Assuming this is the case, I would add that this is not very good code. At the very least, there should be a comment explaining what this is doing. Even better would be to break whatever side-effect is happening out into its own method, so that it can be called explicitly instead of relying on the date setter even in cases where the property value shouldn't be changed.
Looking at the code you posted, the setDate: method is performing some view setup, so doing self.date = self.date; is the author's way of forcing this setup to be done without changing the set date. This would be better done if that view setup code was factored out of setDate:, so that it would simply make a call to do that setup after a new date is set. Then in your above code, it could simply call that setup method, something like updateDateViews or something along those lines.
As for your question about the code calling [super layoutSubviews];, it is always a good idea any time you override a method to call the superclass implementation, unless you know for sure what the superclass implementation does and you know that you don't need to call it, and in rare cases specifically don't want to call it. So a good rule of thumb is to just always add the call to the superclass method. It's the same as when you override viewWillAppear:, viewWillDisappear:, etc. You should always be calling the superclass implementation for those.
I would like to set a member variable in a derived object before i call [super init].
All I can find is that you should not do such a thing. My worakround, to do it anyhow, works, but actually I like to know what the consequences are when bending the rules. Or even better if there is a correct way to deal with this.
The Details:
I have several wrappers that bind a c++ object to an objective-c objec (mostly UI...View or UI...Controller)
#interface my_scrollview : UIScrollView
{
my_c_class* m_p;
}
-(id) initWithFrame:(CGRect)frame wrapper: (my_scrollview*) pWrap;
-(void) setContentOffset:(CGPoint)contentOffset;
#end
#implementation dwin_scrollview_ios
-(id) initWithFrame:(CGRect)frame wrapper: (my_scrollview*) pWrap
{
m_p = pWrap; // illegal but works?
return [super initWithFrame: frame];
//m_p = pWrap; // to late because [super init...] already called overriden func.
}
In my overwritten setContentOffset-method I need to access my C++-Object.
The Problem arises because the initWithFrame internally initializes its content using setContentOffset. So this method is called before I could "legaly" set up the link to my c++-object.
I can implement my overrides with a check if m_p is set(luckily it's initialized to nil). But I have to synchronize the state of the view and my c++-object after the the init-method. In this example this is no big deal but other such realtions are much more complicated and I end up with lot of code that repeats steps of the initialization or otherwise brings me back in sync, although before the [super init...] I know I was in sync.
Is there a pattern to solve this correct (and elegant)?
Is it really so bad to int the pointer before the call to [super init..];?
(I assume one consequence is that this crashes if [super init] returns nil...? any other cases?)
Thanks in advance
Moritz
There is nothing magical about init methods in Objective-C. alloc returns an object of the class that you want, with all instance variables initialized to 0 / nil / NULL / 0.0 etc. Each init method then just executes the code that the developer has written.
There are things that are obviously stupid, like setting an instance variable of the superclass, then calling [super init] which promptly overwrites it. And you need to be aware that init doesn't necessarily return self, but a different object, in which case everything you've initialised in the base class before calling [super init] will be gone.
// illegal but works?
No, it's not illegal. It's perfectly legitimate, although unconventional, to do stuff to an object before its superclass' initializer has been run. It may still lead to unexpected behavior and bugs, but it's not illegal per se. Sometimes it's even necessary, for example when you want to perform some computation and delegate the result of that computation to the superclass' initializer.
You are using wrong init
try this:
-(id) initWithFrame:(CGRect)frame wrapper: (my_scrollview*) pWrap
{
self = [super initWithFrame: frame];
if (self) {
m_p = pWrap;
}
return self;
}
Since being an OS X/iOS Developer for years I have a strong interest in Apples Swift language. In order to keep my initialization methods clean and simple I am isolating individual parts of the initialization into individual methods. Especially when dealing with long initializations - like often found in a SpriteKit SKScene subclass this helps me keeping a clean and simple structure. This is how it looks like:
Typical Objective-C Class:
#interface SomeScene ()
#property (strong, nonatomic) SKSpriteNode* backgroundNode;
#property (strong, nonatomic) SKNode* hudNode;
#property (strong, nonatomic) SKSpriteNode* playerNode;
#end
#implementation SomeScene
-(id)init {
if (self = [super init]) {
[self setupBackgroundNode];
[self setupHUD];
[self setupPlayer];
}
return self;
}
-(void)setupBackgroundNode {
self.backgroundNode = [SKSpriteNode new];
self.backgroundNode.position = CGPointMake(0., 0.);
/* Some More Options */
[self addChild:self.backgroundNode];
}
-(void)setupHUD {
self.hudNode = [SKSpriteNode new];
self.hudNode.position = CGPointMake(0., 0.);
/* Some More Options */
[self addChild:self.hudNode];
}
-(void)setupPlayer {
self.playerNode = [SKSpriteNode new];
self.playerNode.position = CGPointMake(0., 0.);
/* Some More Options */
[self addChild:self.playerNode];
}
#end
This is just a demonstration to show you how I encapsulate different parts of the initialization into individual methods which are then all being called at the time the -(id)init is being called. I am using this kind of pattern in any of my projects.
Now with learning Swift I read about the basic concepts, about optionals and tried to get used to the slightly different type of initialization. And in order to keep my own Objective-C pattern shown above the Swift code will look like this:
Same class in Swift:
class SomeScene: SKScene {
var backgroundNode: SKSpriteNode?
var playerNode: SKSpriteNode?
var hudNode: SKSpriteNode?
override convenience init() {
self.init()
self.setupBackground()
self.setupPlayer()
self.setupHUD()
}
func setupBackground() {
backgroundNode = SKSpriteNode(/*Some Initialisation Parameters*/)
backgroundNode?.position = CGPointMake(0.0, 0.0)
/* even more lines */
self.addChild(backgroundNode!);
}
func setupPlayer() {
playerNode = SKSpriteNode(/*Some Initialisation Parameters*/)
playerNode?.position = CGPointMake(0.0, 0.0)
/* even more lines */
self.addChild(playerNode!);
}
func setupHUD() {
hudNode = SKSpriteNode(/*Some Initialisation Parameters*/)
hudNode?.position = CGPointMake(0.0, 0.0)
/* even more lines */
self.addChild(hudNode!);
}
}
This does work like expected but I was asking myself if this is the correct way of using optionals. I am afraid that I am misusing them just to convert an Objective-C style to Swift. Do I really have to write all that question marks after every property? Does that something or is it more of a way to switch of a compiler-error that this property "might be nil" - which is what Apples Documentation says about the ?-suffix.
I came up to this question because using swift that way feels a bit strange. Is there a better way to encapsulate code-parts / blocks from an init method in order to prevent it from growing and growing and loosing focus ?
Do I really have to write all that question marks after every property?
Basically, yes. Swift has strong rules about initializers. You must initialize all instance properties by the end of initialization. If you are going to move initialization of instance properties out of the initializer, then you must provide a default initial value for those instance properties in some other way. You can do that with an equal sign and an explicit value, or you can do it with an Optional because it automatically assigns nil.
That is why outlets (#IBOutlet) are usually Optionals. We know they won't be initialized during initialization, so we need a temporary value until they are initialized when the nib loads.
Also it is common practice to use Optionals for any instance property that simply cannot be initialized until after the instance itself has been fully initialized. For example, you might have some time-consuming operation to perform, and you don't want to do that in the initializer.
However, there is another approach that might be appropriate for some of your instance properties: mark them as lazy and provide a default initializer that is a define-and-call function. For example:
lazy var prog : UIProgressView = {
let p = UIProgressView(progressViewStyle: .Default)
p.alpha = 0.7
p.trackTintColor = UIColor.clearColor()
p.progressTintColor = UIColor.blackColor()
p.frame = CGRectMake(0, 0, self.view.bounds.size.width, 20)
p.progress = 1.0
return p
}()
That has the advantage of encapsulation. We have provided a default value, namely the thing returned from the define-and-call function, so we don't have to initialize in an initializer. But the compiler allows us to postpone running the define-and-call function until the first time some other code actually accesses this instance property. That pattern might make more sense for you.
Also I find myself using computer properties a lot. That's another good alternative pattern in many cases.
So basically yes, what you are doing is right, but Swift has some other patterns that can often make it unnecessary, and when you're coming from Objective-C you'll want to get comfortable with those patterns too.
Im trying to make it so that every single UIControl in my application (UIButton, UISlider, etc) all have special extra properties that I add to them.
I tried to accomplish this by creating a UIControl Category and importing it where needed but I have issues.
Here is my code.
My setSpecialproperty method gets called but it seems to be getting called in an infinite loop until the app crashes.
Can you tell me what Im doing wrong or suggest a smarter way to add a property to all of my UIControls?
#interface UIControl (MyControl)
{
}
#property(nonatomic,strong) MySpecialProperty *specialproperty;
-(void)setSpecialproperty:(MySpecialProperty*)param;
#end
////////
#import "UIControl+MyControl.h"
#implementation UIControl (MyControl)
-(void)setSpecialproperty:(MySpecialProperty*)param
{
self.specialproperty=param;
}
///////////////
#import "UIControl+MyControl.h"
#implementation ViewController
UIButton *abutton=[UIButton buttonWithType:UIButtonTypeCustom];
MySpecialProperty *prop=[MySpecialProperty alloc]init];
[abutton setSpecialproperty:prop];
While you can't add an iVar to UIControl via a category, you can add Associated Objects, which can be used to perform much the same function.
So, create a category on UIControl like this:
static char kControlNameKey;
- (void) setControlName: (NSString *) name
{
objc_setAssociatedObject(self, &kControlNameKey, name, OBJC_ASSOCIATION_COPY);
}
- (NSString *) controlName
{
return (NSString *)objc_getAssociatedObject(array, &kControlNameKey);
}
There's more to it than that, I guess you'll need to check if an association exists before setting a new one, otherwise it will leak, but this should give you a start.
See the Apple Docs for more details
self.specialproperty=param is exactly the same as calling [self setSpecialproperty] (see here for some totally non biased coverage of Obj-C dot notation), which makes your current usage infinitely recursive.
What you actually want to do is:
-(void)setSpecialproperty:(MySpecialProperty*)param
{
_specialproperty = param;
}
Where _specialproperty is the implicitly created ivar for your property.
I'm assuming there's some reason why you've implemented your setSpecialproperty setter? Why not just use the one that is implicitly created for you?
the problem is that you can not add a property to a category, you can add behavior (methods) but not properties or attributes, this can only be done to extensions, and you can not create extensions of the SDK classes
use your method as
change your method name to
-(void)setSpecialproperty:(MySpecialProperty *)specialproperty
-(void)setSpecialproperty:(MySpecialProperty*)specialproperty
{
if(_specialproperty!=specialproperty)
_specialproperty = specialproperty;
}
and synthesize your specialProperty as
#synthesize specialproperty=_specialproperty;
I want' to implement "Fix and continue functionality" that was in Xcode 3.
CONTEXT:
The main idea is:
When I need to "Fix something fast", I'm not re-compiling, project. I'm compiling small Attacker class with 'updated' method implementation, loading it into memory and replacing VictimClass's method which have incorrect implementation in runtime.
I think that this method will work faster that full project recompilation.
When i'm done with fixes i'm just copying source of Attacker class method to Victim class.
PROBLEM
At the moment, I don't know how correctly call [super ...] in Attacker class.
For example, i have VictimClass
#interface VictimClass : UIView #end
#implementation VictimClass
- (void)drawRect:(CGRect)rect {
[super drawRect:rect];
}
#end
#interface AttackerClass : NSObject #end
#implementation AttackerClass
- (void)drawRect:(CGRect)rect {
[super drawRect:rect];
[self setupPrettyBackground];
}
#end
....
// EXCHANGE IMPLEMENTATIONS
Method m = class_getInstanceMethod([AttackerClass class], #selector(drawRect:));
const char * types = method_getTypeEncoding(m);
IMP attackerImp = method_getImplementation(m);
class_replaceMethod([VictimClass class], #selector(drawRect:), attackerImp, types);
// Invoking drawRect on Victim
VictimClass * view = /* */;
[view setNeedsDisplay];
At this point , when drawRect: method will be called, this will lead to exception, since drawRect: will be called on NSObject class, but not on UIView class
So, my question is, how correctly call [super drawRect:] in AttackerClass, to have possibility to correctly exchange implementation in runtime?
Main idea is to provide a way to correctly replace any method in Victim class by Attacker's class method. Generally, you don't know, superclass of Victim class.
UPDATE: Replacing implementation code added.
You will have to
get the receivers class (e.g. with object_getClass(rcv))
then get the super class of it (with class_getSuperclass(class))
then get the implementation of it (with class_getMethodImplementation(superclass, sel))
then call the imp.
done
Stop at any step if you got nil or NULL.
Oh, and all this seems silly. But I assume that the question just lacks of context to see the motivation for such a hack.
[Update]
An explanation for future readers:
The super keyword is resolved at compile time. Therefore it does not the intended thing when changing methods at runtime. A method which is intended to be injected in some object (and its class hierarchy) at runtime has to do super calls via runtime as outlined above.
Assuming that the runtime changes you're making involve modifying the superclass, you'll have to do something like this:
#implementation AttackerClass
-(void) drawRect:(CGRect)rect
{
if( [super respondsToSelector:#selector(drawRect:)] )
{
[super drawRect:rect];
}
[self setupPrettyBackground];
}
#end
This will check if the superclass "knows about" drawRect:, and doesn't call it in the case that super has no drawRect: selector.
Hence, when the superclass is NSObject the drawRect: message will not be sent. When you change it to UIView at runtime (whatever your reason for that is), the message can safely be sent.
One approach is to use objc_msgSendSuper. Your method -[AttackerClass drawRect:] will have the following implementation:
- (void)drawRect:(CGRect)rect {
struct objc_super superTarget;
superTarget.receiver = self;
superTarget.class = object_getClass(self);
objc_msgSendSuper(&superTarget, #selector(drawRect:), rect);
[self setupPrettyBackground];
}
but why do you need to call draw rect method for superclass NSObject, when NSObject hasn't got that method? just don't do it... call it just in VictimClass drawrect