self.property = self.property in objective c - ios

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.

Related

animator.startAnimation -- What does this warning mean?

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

do something before [super init] in objective-c

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;
}

Trying to create a custom initializer method

So I know there a bunch of questions like this but none of their solutions seems to be helping me.
Let me start of by saying I am using storyboards so I would use initWithCoder instead of initWithNibName:.
Now that we got that bit out of the way. So, simply I want to pass an object to another view with a custom initializer.
So in my second view I would have code like this:
- (id) initWithMyLifeChangingObject: (MagicType *)object {
//Apparently this is important
self = [super init];
//Do some stuff with my magical object
//You know the story
return self;
}
And as the story goes you need to call your world class init:
[SecondClass alloc] initWithMyLifeChangingObject:object];
But initWithMyLifeChangingObject: isn't recognized and gives me a build error saying it is not in existence... so what do I do.

How to communicate with the delegate in a custom class's init method in Objective-C

I spent much time to get a better understanding in delegation in Objective-C. I got it working for most cases, but there is a problem in a specific case, which I find difficult to understand. Let me explain what I am trying to do:
I have a custom view called GridLayoutView, which is subclass of UIView. I also have a view controller SomeViewController, which is the delegate of GridLayoutView.
I have a custom initWithFrame method, and I am conditionally calling another initialization method baseInit. That method calls a delegate method at some time. Here is some code from GridLayoutView:
//
// Delegator
// GridLayoutView.m
//
#implementation GridLayoutView
- (id)initWithFrame:(CGRect)frame
numberOfRows:(NSUInteger)rows
numberOfCols:(NSUInteger)cols
{
self = [super initWithFrame:frame];
if (self) {
self.numberOfRows = rows;
self.numberOfCols = cols;
self.numberOfCells = rows * cols;
if (self.numberOfCells > 0) [self baseInit];
}
return self;
}
- (void)baseInit
{
// do some more initialization stuff here
// ...
// then call a delegate method
[self.delegate someMethod:someObj];
// However, this method is not called because self.delegate is nil
}
and some code from SomeViewController:
//
// Delegate
// SomeViewController.m
//
#implementation SomeViewController
// ...
// in some method
self.gridLayoutView = [[GridLayoutView alloc] initWithFrame:gridLayoutFrame
numberOfRows:rowsCount
numberOfCols:colsCount];
self.gridLayoutView.delegate = self;
// ...
The delegate method never gets called within baseInit, because the delegate is nil at that time and it gets set after initWithFrame and baseInit methods are done. I have confirmed this.
I sense that there is something wrong in my workflow of delegation. I have a solution but I don't think it is the best way to go. The solution is basically passing the SomeViewController instance to the delegator by modifying the initWithFrame method such as:
- (id)initWithFrame:(CGRect)frame
numberOfRows:(NSUInteger)rows
numberOfCols:(NSUInteger)cols
delegate:(id<GridLayoutViewDelegate>)aDelegate
This approach works, but I am uncomfortable due to passing SomeViewController to GridLayoutView in its initWithRect. I am wondering if this is a good way to go with delegation or is there a better approach? I would be very grateful if someone can clear this for me.
If I'm understanding you correctly, there aren't many options here.
Modifying your initializer (as you suggested) to pass in the delegate. There is nothing wrong with that, don't know why you don't like it.
Remove the dependency on the delegate during initialization and instead, send whatever delegate message is appropriate when the delegate property is set by overriding the setter:
- (void)setDelegate:(id<GridLayoutViewDelegate>)aDelegate
{
_delegate = aDelegate;
// send whatever message makes sense to the delegate
[_delegate someMethod:object];
}
EDIT - noticed your comment
Your initialization method should not take any significant amount of time. It's unclear what you mean by 'loading views'. If you simply mean creating and adding subviews to a view then that is fast and there should be no need to communicate progress to a delegate (which you can't do anyway b/c the initialization is on the main thread and UI won't update until all of init is complete).
If you mean loading data that takes a long time, you should disconnect that from initialization and load the data in a background operation, sending progress messages to a delegate.
i would implement the setDelegate function and then call
[self someMethod:someObj]; from there

Objective C does self point to parent after doing self = [super init]?

When I have code like the following:
self = [super init]
does self point to super? If so, why would you want this? if my instance object has the variable "someVal", I won't be able to get to it by doing [self someVal]. correct?
How then would I get to the instance variable's using self when self points to super?
does self point to super?
It's really the other way around. super is really the same as self, except that it tells the compiler to start looking for method implementations starting with the superclass rather than the class itself. You can check this by logging the value of super and the value of self; you'll find that they both point to the same address.
When you create an object, you do this:
Foo *f = [[Foo alloc] init];
The alloc allocates the memory that will become the object you're creating, but until that memory is initialized it's just a chunk of memory -- not a valid object. If Foo is a subclass of Bar and Bar is a subclass of NSObject, then by convention Foo's initializer will call Bar's, and Bar's will call NSObject's, so that the initialization proceeds in order: first the memory is initialized by NSObjects' -init, and Bar's init receives the returned value and assigns it to self. It then proceeds to do any Bar-specific initialization, and returns self. Foo's -init then assigns the returned value to self again and finally does any Foo-specific initialization.
All that assigning to self might seem both redundant and confusing. It's really just a convention, but the purpose is to allow the superclass's initializer to return some object other than the one that was allocated, including nil. So, for example, if the initialization of Bar failed for some reason, -[Bar init] could return nil. The possibility that nil might be returned from [super init] is the reason we put the self = [super init] assignment inside a conditional: if the assigned value is nil, the initialization part is skipped and nil is returned. It's also possible that -[Bar init] could return a pointer to an object other than the one that was allocated, such as when an object similar to the one being created already exists and can be reused.
Most of the time, the pointer you get back from -init will be the same one that you got from +alloc, so you could write this:
Foo *f = [Foo alloc];
[f init];
If you write that, however, you're making an assumption that the initializers of your class and all the classes that it inherits from will always return the same object, and will never return nil. By doing that you're breaking the convention and severely hamstringing yourself and whoever wrote the classes from which Foo inherits -- they'll break your code if they return a different object in a future release of the class. Also, it'll look like you don't know what you're doing.
does self point to super?
This question doesn't make sense in an instance method, since there super is not really a concrete/actual pointer-to-instance, it just indicates that the implementation of the superclass must be called. And since in the case of most objects (except class clusters) all methods return self;, then the answer is no: the actual pointer to the instance doesn't change magically by itself.
For the record: the exception is manifested by class clusters (most Cocoa container classes, for example, NSString, NSArray, etc.). These classes often have an initializer method that returns a different instance than the one that was originally allocated, and of which the class is a concrete subclass of the class of the original self. For example, an implementation of the NSString initializer could be:
#implementation NSString
- (NSString *)init
{
[self release];
self = [[__NSCFString alloc] init];
return self;
}
#end
The reason for this is that optimizing for different types of initialization can be achieved this way.
Self is always pointing to one instance. When you use super you are referencing parent methods not a parent instance.
self means current class' instance.
self = [super init] means self is getting the value returned by [super init].

Resources