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.
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 am currently loading this code below on every view load. Is there a more performance direction I can take, like a singleton, or is this the best way to load ads in iOS?
- (void)viewDidLoad {
buttonsView.orientation = CSLinearLayoutViewOrientationVertical;
buttonsView.verticalAlignment = CSLinearLayoutItemVerticalAlignmentBottom;
self.ad.adUnitID = #"ca-app-pub-3940256099942544/6300978111";
self.ad.rootViewController = self;
self.ad.delegate = self;
self.ad.adSize = GADAdSizeFromNSValue(NSValueFromGADAdSize(kGADAdSizeSmartBannerPortrait));
[self.ad loadRequest:[GADRequest request]];
[super viewDidLoad];
}
There are a few ways you can do this. One method is to create a UIViewController super class. In the viewDidLoad method of the superclass implement the ad code. Any view which needs this ad code should just inherit from the super class and it get's this behavior. If each UIViewController has specific values to identify it as a unique view you can set this values in the before calling [super viewDidLoad] on super class. If this doesn't make any sense let me know and I can put some code together for you.
Another possible approach is to use method swizzling to modify the default behavior of the UIViewController and add your code this way. Just google "method swizzling objective-C". Here's one of the better articles on this that I like: https://blog.newrelic.com/2014/04/16/right-way-to-swizzle/
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;
}
Coming from a .NET background, I used to make classes that looked a lot like this:
MyClass
Inherits List(Of SomeOtherClass)
I am getting smoked trying to do this in Objective-C. I am wanting to have a class that is a collection of UIImageViews.
I tried this, which is wrong (it inherits from NSArray):
- (id)init
{
//I know I'm not using an imageview here, this was just a proof of concept
self = [super initWithObjects:[UIImage imageNamed:#"btnSideMenu"], nil];
if (self) {
}
return self;
}
The collection is a fixed size, so it won't need to be mutable. However, if using a NSMutableArray provides more syntactical sugar than I would not be opposed to it.
I think a subclass for this is excessive. Subclasses should be used to add functionality to a super class. You should just make an NSMutableArray of UIImageViews
I am in a situation where I have to create an init with a parameter.
- (id) initWithSomeParameter:(id)parameter;
Normal init should not be called. So, I have two choices to accomplish this. I can actually throw an exception when some one calls the init or return nil.
Which should be done and why?
You should have a designated initializer, which all other init methods call.
In your example, the designated initializer would perhaps be
- (id)initWithSomeParameter:(id)something;
If another programmer calls -(id)init instead of the designated initializer, you might do something like this:
- (id)init
{
return [self initWithSomeParameter:nil];
}
If you absolutely must have a value provided for someParameter, you can raise an exception if you choose to, but this practice varies with how important getting a value is on initialization of the instance object.
Here's Apple's input also on using a designated initializer:
http://developer.apple.com/library/ios/#documentation/general/conceptual/DevPedia-CocoaCore/MultipleInitializers.html
It's hard to say without knowing more about your use case. However, Perhaps you are being too strict with your API.
UIKit itself is full of classes that need some data to operate, but don't require it on init. Take UIImageView for example. You may think "an image view requires an image to do anything, therefore I should require an image on init!". However, this snippet here is a perfectly valid use case:
UIImageView *foo = [[UINavigationController alloc] init];
foo.image = [UIImage imageNamed:#"bar"];
Here we make an image view, and assign the image itself in a second step. So instead throw exceptions when you try to use your object in ways that require data to be present if that data isn't present.
Also, your designated initializer is usually the one that typically takes the most arguments, and the rest call that one. Something kind of like this may be more what you want.
- (id)init {
// call this class's designated initializer
return [self initWithSomething:nil];
}
// this class's designated initializer
- (id)initWithSomething:(NSString*)something {
self = [super init]; // call superclass's designated initializer
if (self) {
// this class's setup code goes here, saving any arguments
somethingInstanceVar = something;
}
return self;
}
// some other method.
- (NSString*)doSomething {
if (somethingInstanceVar) {
// all is well, do stuff
return somethingInstanceVar;
} else {
// never got a "something" raise an exception
[NSException raise:#"Missing data" format:#"Something is required!"];
}
}