How to import another view controller header file when I use Objective-C category? - ios

When I want to transition from one view controller to another, I import the second view controller's header file into my first view controller's header file, by writing #import "SecondViewController.h". However, since I already defined UIColor category in my first view controller, when I try to import the second view controller, I enter the following error: Duplicate interface definition class for SecondViewController.
Here's my FirstViewController.h:
#import
#import "SecondViewController.h"
#interface FirstViewController : UIViewController
#end
#interface UIColor (ColorWithInt)
+ (UIColor *)colorWithR:(CGFloat)red G:(CGFloat)green B:(CGFloat)blue A:(CGFloat)alpha;
#end
I didn't meet any such errors so far when I develop this app, so it's definitely this category that is causing the issue here. So is it feasible to use category when I want to import another view controller class? Or are there any alternative ways to extend UIColor? I just want to define a function that takes RGB as 0 ~ 255 integer, not 0 ~ 1 floating values that UIColor uses on default.
I use iOS 7 and Xcode 5.

You might #import "SecondViewController.h" twice, just check FirstViewController.h/m file if both did that.

I have a feeling you're using this
#interface
instead of
#implementation
in your .m file.

Self Answer
I found out that the issue is not related to either FirstViewController or SecondViewController - let alone the category; it's because I imported almost all class' header file in AppDelegate.h in order to initialize the relationship among UITabBarController, UINavitationController, RootViewController, and Core Data and its lots of required properties. I didn't know that when I import a class in AppDelegate.h I cannot import the class at some other class's header file. Delete #import "FirstViewController.h"; and #import "SecondViewController.h;" in AppDelegate.h and I find my app being build properly now. Thanks to those who left comments in this post.

Related

Swift test unable to find Swift class property on Objective-C VC

I may be in compiler hell right here.
I'm implementing a Snapshot test in Swift, calling a property on an Objective-C VC, but that property is a class, written in Swift, bridged in.
In MyViewController.h:
#class TextEntryView;
#interface MyViewController: AbstractTextEntryViewController
#property (nonatomic, strong) TextEntryView *textEntryView;
#end
In TextEntryView.swift:
#objc(TextEntryView) class TextEntryView: UIView
And in my test, I'm trying to call
vc.textEntryView where vc is of type MyViewController and I'm getting the error:
value of type MyViewController has no member textEntryView
My bridging headers look good. If I add an NSString property to the .h file above, I'm able to reference it in the test. Also, when I command-click on MyViewController in my test, it takes me to the .h file rather than the .swift generated version of that file (which seems like a symptom of this problem).
I may be pushing Xcode 8 beyond its limits.
You need to make sure you import your app at the top of the source file for your test. For example, if your app is called MyApp, insert at the top of the test file:
import MyApp
If I leave out the import, I get the same behavior you are seeing. Additionally, as long as the import is there, you shouldn't have to bother with bridging headers for the unit test.
Have you tried to import to Test Target ?
Since you already imported the Xcode-generated header file for your Swift code into Objective-C .m file.
Please also remove #objc annotation from TextEntryView class since it's a subclass of UIView thus accessible and usable in Objective-C. keeping the annotation #objc may cause a side effect.
To be accessible and usable in Objective-C, a Swift class must be a
descendant of an Objective-C class or it must be marked #objc.
a simple case of "side-effect" is when a (swift) UIViewController subclass is marked #objc and used as custom subclass in storyBoard:
instantiateViewControllerWithIdentifier will instantiate a UViewController instead of the subclass we set in the storyBoard.
with error Unknown class _TtC10AbcdViewController in Interface Builder file

how to slim down view controllers in iOS?

How you guys slim down your view controllers?, sometimes you end up implementing a lot of protocols in your view controller, so there’s a lot of code inside the controller itself. Reading about how to slim down view controllers in iOS I found that a common way is to move DataSources (http://www.objc.io/issue-1/lighter-view-controllers.html) to other class, but what about other delegates?, or if you create views by code?. First, I think about move each delegate to a NSObject class, so I try this:
self.locationManager.delegate = [[FRRYPetDescriptionViewControllerLocationDelegate alloc] init];
Then I ask in IRC and somebody suggest categories, so this is what I got so far:
// FRRYPetDescriptionViewController.h
#interface FRRYPetDescriptionViewController : UIViewController
#property (nonatomic) CLLocationManager *locationManager;
#property (nonatomic) TPKeyboardAvoidingScrollView *scrollView;
#property (nonatomic) UIView *contentView;
#end
// FRRYPetDescriptionViewController+Protocols.h
#interface FRRYPetDescriptionViewController (Protocols) <UITextViewDelegate, UIActionSheetDelegate, MFMailComposeViewControllerDelegate, UIGestureRecognizerDelegate, MKMapViewDelegate, UIViewControllerTransitioningDelegate, CLLocationManagerDelegate>
#end
// FRRYPetDescriptionViewController+UIAdditions.h
#interface FRRYPetDescriptionViewController (UIAdditions)
- (void)createScrollView;
- (void)createContentView;
#end
// FRRYPetDescriptionViewController+Callbacks.h
#interface FRRYPetDescriptionViewController (Callbacks)
#end
// FRRYPetDescriptionViewController+LocationAdditions.h
#interface FRRYPetDescriptionViewController (LocationAdditions)
#end
This makes me think, what about “private” methods?, do I need to declare all properties in the view controller header file?. What you guys think about this approach or there’s some common pattern to follow to not end with a fat controller?.
Thank you.
The link that you have referred to has beautiful explanation for less bulky controller's programming. But techniques are bit tricky unless you are a seasoned developer. You have asked about multiple techniques in your question. Please check my views on them below: -
Delegates - I personally prefer to keep the delegate code in my controller itself to avoid unwanted confusion specially when you are working with multiple scenarios within the same controller.
Create Views Programmatically - This is the portion where we can cut the large amount of code from UIViewController. Unless it is a single control such as a single label or button, we should make a custom UIView class and let it set all the common properties for view customisation. Controller should only invoke it with necessary parameters.
Properties in Header File - No, concept of data encapsulation says that we should only make those variables public which are required. Rest should move to private domain so that we external objects can't interfere with the class object functionality. So you should declare these properties in class extension (inside .m file). Moreover it is not required to have all variables as properties, when they are private you can declare them as instance variables as property declaration does nothing but to create the getter/setter for that variable.
Private Methods - Same goes to methods as well. If it doesn't have to be exposed to other objects; it should not be in header file. Keep it in extention as private method.

Multiple Class in one file

Recently I was studying the possibility of creating multiple classes in only one file, for this I created a class of UIViewController with a .xib file, the structure of the file is as follows:
MyFristViewController.h
#import <UIKit/UIKit.h>
#interface MyFristViewController : UIViewController
#end
#interface MySecondViewController : UIViewController
#end
MyFristViewController.m
#implementation MyFristViewController
- (void)viewDidLoad {
[super viewDidLoad];
NSLog(#"Frist View Loaded");
}
#end
#implementation MySecondViewController
- (void)viewDidLoad {
[super viewDidLoad];
NSLog(#"Second View Loaded");
}
#end
My doubt is: How does the system know that is to perform the methods contained in the class called 'MyFristViewController'?
I already tried to modify the custom class in interface builder, tried to change the position of the classes in the file and the system continues running only the existing methods inside the 'MyFristViewController' class why?
How does the system know that is to perform the methods contained in the class called 'MyFristViewController'?
The filenames are irrelevant. When looking at a class, for the most part, the code between #implementation <#ClassName#> and #end is used.
Additional customization of classes can be added through categories and class extensions. These can also be specified in the same file, or different files, because (again) the filenames are irrelevant.
Generally, you should have one class per file to make it easy to read and find your code. See How many classes should a programmer put in one file? for additional discussion.
My doubt is: How does the system know that is to perform the methods contained in the class called 'MyFristViewController'?
Because the methods are in the #implementation block of MyFristViewController.
I already tried to modify the custom class in interface builder, tried to change the position of the classes in the file and the system continues running only the existing methods inside the 'MyFristViewController' class why?
Probably because you've linked them to the methods in first #interface section in your header file. Control-drag to the actual method you want to bind to. It's not clear what problem you're actually seeing.
That said, this is a terrible idea. Put each view controller in its own file. It'll work in one file, but it will create lots of confusion, as you're seeing.
I have worked on projects that define multiple classes in a single file. I loathe this practice. I find it very disorienting and I waste a lot of time searching for where the classes are defined/implemented.
I would advise you not to do this. It ends up being very confusing.

iOS Xcode - Multiple self delegates in single set of h/m files?

I'm a huge noob, let's get that straight.
Currently I have in my header file...
#interface ViewController : UIViewController <UIWebViewDelegate>
...but can I have multiple delegates in the h/m files?
Can I add somehow?
The reason I ask this, is because of a warning I'm getting...
"Assigning to 'id' from incompatible type 'ViewController *const __strong'"
The app works fine, but I want to make sure the code is 100% proper.
(LONG STORY SHORT, I'm trying to add location tracking to my app, and I did, and it works fine, but it's giving me a warning because I'm 100% positive I didn't implement it properly, as I am trying to have multiple "XXX.delegate = self;" going on.
I want to somehow have...
self.locationManager.delegate = self;
AND
tapView.delegate = self;
in the same "-(void)viewDidLoad"...
Again, I expect people to literally say "Wtf are you smoking, you are doing this all wrong", because I am.. I need help. Please help. I've been googling all day.
That was a very long winded way of asking how to do this:
UIViewController <UIWebViewDelegate, UITextFieldDelegate, UITableViewDelegate>
There is no issue in doing this at all. You must specify the protocol to remove the warning
You can confirm multiplay delegates i.e.
#interface ViewController : UIViewController <UIWebViewDelegate,SomeOtherDelegate>
Well, you can conform to multiple protocols in your .h file like that:
#interface ViewController : UIViewController <UIWebViewDelegate, UITableViewDelegate, UITableViewDataSource>
Ad you can also conform to more protocols in your .m file with a private class extension like that:
#interface ViewController () <UICollectionViewDataSource, UICollectionViewDelegate>
Don't mix them up
in .h file
#interface YourControllerClass : UIViewController <UIAlertViewDelegate, UIWebViewDelegate UITextFieldDelegate>
You can add Delegates when ever you need them. These Delegates have their methods defined. You can use their methods as you wish

issue with ivar

I'm subclassing a UIToolbar because I'm gonna reuse it all over my app. The UIToolbar uses a delegate protocol:
//
// UIToolbarCustom.h
//
#import <UIKit/UIKit.h>
#protocol UIToolbarCustomDelegate
#required
- (void)tab:(UIBarButtonItem *)sender;
- (void)ok:(UIBarButtonItem *)sender;
#end
#interface UIToolbarCustom : UIToolbar {
id <UIToolbarCustomDelegate> delegate;
}
#property (strong, nonatomic) id delegate;
#end
The standford iOS development course teacher recommends to explicit declare all the ivars prefixing it with a underscore, like:
#implementation UIToolbarCustom
#synthesize delegate = _delegate;
#end
But, in this specify scenarion it gives me a error:
error: property 'delegate' attempting to use ivar '_delegate'...
The code works just fine if I use:
#synthesize delegate = __delegate; or
#synthesize delegate;
What is going on here? Is there a private instance variable in the UIToolbar class named _delegate?
UPDATE
Thank all you guys for all the clarifications and protips, I'm learning a lot. Turns out that I'm new to iOS development (this is my first app second version, so I'm trying to do it right =p). Following the tips I came out with this new header file:
//
// Toolbar.h
//
#import <UIKit/UIKit.h>
#protocol ToolbarDelegate
#required
- (void)tab:(UIBarButtonItem *)sender;
- (void)ok:(UIBarButtonItem *)sender;
#end
#interface Toolbar : UIToolbar
#property (strong, nonatomic) id delegate;
#end
Notes:
The class prefix was removed.
The delegate declaration was removed (I'm using a ios delegate tutorial code, but the code sample uses a older xcode version, where the declaration is needed).
The synthesize was removed, I also didn't knew that we don't need synthesize our properties anymore.
PS: Obviously the code does not work, because the ivar problem. I'm gonna change its names, so I don't need to synthesize it, not sure about what name to use anyways...
What is going on here? Is there a private instance variable in the UIToolbar class named _delegate?
Yes, that's exactly the problem. You need to come up with a different name for your instance variable. __delegate will work, or you could prefix the name with a 3 letter prefix (see last paragraph).
Do note that you've declared your ivar as delegate, then in the synthesize statement told the compiler to use _delegate. Effectively that means that your delegate ivar isn't being used at all. In any case, if you're writing for iOS (as opposed to 32-bit Mac), like you are, you don't need the explicit instance variable declaration in your subclass's #interface section, because the compiler will automatically create it for you.
Finally, it's bad form to name your own subclass something that begins with 'UI', since the UI prefix is reserved for classes that are part of UIKit. You should use your own 3 letter prefix instead, or else no prefix at all. The problem is that a future version of UIKit could conceivably include a class called "UIToolbarCustom", and your subclass would collide with it.
Since last year, when Xcode 4.3 came out, you don't need to synthesize your properties. It is done for you by the compiler (an ivar is generated, and a leading underscore is added to its name). This means that you also don't need to declare an ivar. If you do, be sure to name it something other than _delegate.
So, all you really need is this line:
#property (strong, nonatomic) id<UIToolbarCustomDelegate> delegate;
UPDATE: please see the Andrew Madsen's answer for the full story. Turns out UIToolbar has its own ivar named _delegate. Who knew!

Resources