IBOutlet property of the type - ios

I'm trying to install a pre-made custom progress bar in my app and according to the tutorial from the website i got the code from, i need to:
"On the view controller's header file create an IBOutlet property of the type MCPercentageDoughnutView and link it to the object you created on the Interface Builder."
Can someone explain me how do I create an IBOutlet property of the type MCPercentageDoughnutView? I tried doing:
__weak IBOutlet MCPercentageDoughnutView *pieChart;
It gives me the error: Unknown type name 'MCPercentageDoughnutView'. What am i doing wrong?

In header file you should also:
#import "MCPercentageDoughnutView.h"

If the IBOutlet is to be declared in header file, you can do a forward declaration of MCPercentageDoughnutView in the header file and import the class MCPercentageDoughnutView.h file in your implementation file.
#class MCPercentageDoughnutView // In your header file
#import "MCPercentageDoughnutView.h" // In your implementation file
However, if the IBOutlet is to be declared in the implementation file (in your class' extension), the forward declaration in header file is not required.

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

No visible interface for selector - for IBOutlet

That's a weird one:
I'm using a DMSplitView instance
Dragging it to my AppDelegate.h which creates an outlet like #property (weak) IBOutlet DMSplitView *verticalSplit;
However, whenever I'm trying to access it, in my AppDelegate.m, I'm getting an error:
No visible #interface for 'AppDelegate' declares the selector verticalSplit
How is that possible? I've done that like 10,000 times before. What sort of bug is that? Any ideas?
P.S. Just tried it as an experiment, and it's official: I cannot add any outlet whatsoever. :S
How are you defining DMSplitView? Did you use the #class directive in the header file? Did you import it in the .m file? Just wondering.

using #property or #interface in header

What is the right method of declaration if I want to use single object in my viewcontroller?
to use a #property i my .m file
#property (nonatomic, strong) UITextView *resolutionText;
#property (nonatomic, strong) AWLResolutionView *myView;
or to declare them in my .h file
#interface
{
#private
UITextView *_resolutionText;
AWLResolutionView *myView;
}
For the sake of clean coding I would prefer creating properties in the anonymous category inside the .m file.
However, using #property creates automatically an instance variable for you that has the same name as your property preceded by an underscore (_), that can be accessed from within the .m file. This is called synthesising.
Y
ou can also manually synthesize a property to a custom instance variable using #synthesize.
Apple provided some clear instructions how to write clean code in their developer library.
The best way to declare the private variable should be declared as #property in the extension of .m file . If you see in your .m file there is an extension class called as #interface by default, so declared the same in the extension class. Also no need of writing extra code in.h file for declaring the private variable.
So your first approach is best.

NSUnknownKeyException in Apple's HelloWorld tutorial

I'm a noob to iOS development, so am following the HelloWorld tutorial here. I've got to the stage where I'm testing the app after adding the button, text field and label. I have followed the tutorial to the letter as far as I'm aware and I'm getting this error when I run the app:
2013-07-13 15:26:39.629 HelloWorld[1304:11303] * Terminating app due
to uncaught exception 'NSUnknownKeyException', reason:
'[<HelloWorldViewController 0x7566000> setValue:forUndefinedKey:]:
this class is not key value coding-compliant for the key label.'
* First throw call stack: (0x1c90012 0x10cde7e 0x1d18fb1 0xb79e41 0xafb5f8 0xafb0e7 0xb25b58 0x22f019 0x10e1663 0x1c8b45a 0x22db1c
0xf27e7 0xf2dc8 0xf2ff8 0xf3232 0x423d5 0x4276f 0x42905 0x4b917 0xf96c
0x1094b 0x21cb5 0x22beb 0x14698 0x1bebdf9 0x1c13f3f 0x1c1396f
0x1c36734 0x1c35f44 0x1c35e1b 0x1017a 0x11ffc 0x1f9d 0x1ec5)
libc++abi.dylib: terminate called throwing an exception
The code generated in HelloWorldViewController.m is:
#import "HelloWorldViewController.h"
#interface HelloWorldViewController ()
#property (weak, nonatomic) IBOutlet UILabel *label;
#property (weak, nonatomic) IBOutlet UITextField *textField;
- (IBAction)changeGreeting:(id)sender;
#end
#implementation HelloWorldViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)changeGreeting:(id)sender {
}
#end
And in HelloWorldViewController.h:
#import <UIKit/UIKit.h>
#interface HelloWorldViewController : UIViewController
#end
I tried using this answer but I can't see an XIB file (I think because I'm using a Storyboard?) and I can't see any obvious discrepancies in the VC.
Please help.
A storyboard is a single file that encapsulates a collection of XIB files. Each "scene" in a storyboard represents what would otherwise be a single XIB file.
In the storyboard...
(1) Select the View Controller in the relevant scene.
(2) Open the Identity Inspector (third tab in the right-hand Utilities pane). Check that the view controller's class is correctly set to HelloWorldViewController.
(3) check that the View Controller's IBOutlets are correctly wired up to the correct views. (Ctrl-click on each view and check it's settings in the HUD).
'Wiring up' entails CTRL-dragging from your viewController to the relevant view in your storyboard scene. A list will appear of appropriate IBOutlet properties to select.
These properties can be placed either in the interface declaration in the .h file or in a class extension in the .m file.
An interface declared as #interface (in the .h file) is public; A class extension declared as #interface() (usually in the .m file) is private to the class (although nothing is completely private in Obj-C). Class extensions are useful for declaring private properties, or properties that are publicly readonly and privately readwrite. See the apple docs. They used to be good for declaring private methods, but now this is redundant: methods only need declaring if we want to make them public.
A good rule of thumb is wherever possible, keep your declarations in the class extension and out of the .h file. These days this should only apply to properties as method declarations are not required unless making them public.
You mentioned that you fixed your problem by moving your property declarations from the class extension to the public interface. This is puzzling, as both locations are normally acceptable for this use.
I removed all referencing outlets and actions which you can see at connection indicator while selecting objects one by one at storyboard workspace, and deleted some codes added automatically by xcode.
And then I made them by following tutorials again. finally it worked fine.

Connecting IBOutlets, variable, property or both?

When using IB in combination with assistant view you control-drag an element in the IB to the .h file and create an outlet. You can drag it to one of 2 place, either inside the variable declaration block or outside the block.
If you drag it inside the variable block you get something like this:
#interface MyViewController : UIViewController {
IBOutlet UIButton *foo;
}
dragging it outside the block gives you something like....
#interface ViewController : UIViewController {
}
#property (retain, nonatomic) IBOutlet UIButton *foo;
I've thought about how they are different and I'm a little confused. Ok, I understand synthesized properties do some magic and create instance variables at runtime (only on 64bit/ARM). So I believe I understand how the 2 options work.
What's the best option though? First option generates less code and seems simpler.
Second version offers public accessors/mutators, but I rarely access outlets from outside my class (and if I do, it's almost always with encapsulation). From the time I've started iOS work I've exclusively used this option.
Am I missing anything or should I make the switch to variable based outlets in most cases?
The ability to declare IBOutlet in the property declaration is relatively new #property (retain, nonatomic) IBOutlet UIButton *foo;
Previously, you had to declare IBOutlet UIButton *foo inside the curly braces and then synthesize the property. Now, declaring the IBOutlet in the curly braces is redundant.
You have two options to declaring the properties now. Option 1 is to declare it in your .h file, which will make it public. Alternatively, you can create a private interface in your .m file using:
#interface MYCLASS()
#end
and declare your properties there. This is my preferred way of doing it unless I need public access to that property (which should be the exception, not the norm if you are obeying MVC conventions).
Short answer: It doesn't make a much of a difference either way.
Long answer: If you want set/mutator methods, then drag outside of the block. If you don't care about methods and are just going to access the variables directly then putting them in as straight variables inside the block is probably the way to go.
Public visibility:
If you just specify the IBOutlet as a variable then you can use #private or #protected to prevent outside access. If you really want a #property for some reason you can still control public visibility by moving the property out of the .h and into a class extension in the .m file.
Conclusion: Myself, I'm sticking with the straight variable declaration and save the other options for when I need something extra.
IBOutlets are best inside of the block, unless you really plan on working with it in the .m file.
Remember, you can have both. The one inside of the variable block is essentially, in all basics, just for when you use it in IBActions.
The property can be used in the .m file for further customization.
Again, you can use both, it just depends on the extent you're using it.

Resources