How can Interface Builder interact with private IBOutlet? - ios

I see that IB job is to unarchive the Nib file, load the objects in the Nib and set those to IBOutlet properties. Some people even use IB as DI framework
But IBOutlet can be private, I mean it can be declared in class extension or implementation section. So how can IB interact with these private IBOutlet?
#interface FPMovieBottomViewController ()
#property (weak, nonatomic) IBOutlet UILabel *usernameLabel;
#end

As described in the Note here: Customizing Existing Classes
By adding the class extension shown above, redeclaring the
uniqueIdentifier property as a readwrite property, a
setUniqueIdentifier: method will exist at runtime on every XYZPerson
object, regardless of whether other source code files were aware of
the class extension or not.
The compiler will complain if code in one of those other source code files attempts to call a private method or set a readonly property, but it’s possible to avoid compiler errors and leverage dynamic runtime features to call those methods in other ways, such as by using one of the performSelector:... methods offered by NSObject.
You should avoid a class hierarchy or design where this
is necessary; instead, the primary class interface should always
define the correct “public” interactions.
If you intend to make “private” methods or properties available to select other classes,
such as related classes within a framework, you can declare the class
extension in a separate header file and import it in the source files
that need it. It’s not uncommon to have two header files for a class,
for example, such as XYZPerson.h and XYZPersonPrivate.h. When you
release the framework, you only release the public XYZPerson.h header
file.
I've highlighted the parts where we can modify existing classes with dynamic runtime. In other languages such as ruby or python this is called monkey-patching.
There's a good article about this: monkeypatching-for-humans. But, in the example given, extension only allows one to add functionality to existing classes, not replace, remove or override. In objc, an accurate example of monkey patching is method-swizzling. Which is not always harmful, because developers have been taking advantage of it to build something like Xcode plugins, or mogenerator.

Related

IOS Swift - Removing a inherited property from a class when implementing from SDK

I am attempting to use a Default Layout View Controller from a Software Developer Kit. This Default Layout contains elements of a generic UI which can be used for quick deployment and still allowing full functionality of the kits purpose. I am attempting to learn how to exclude certain members of a class I pull from this kit. I am more conceptually trying to understand how I would go about doing this.
Lets say this view controller class I am using has 4 class members that are properties (among other members that are methods, other properties)
Class: DefaultLayoutViewController
Properties:
topViewController
bottomViewController
leftViewController
rightViewController
I wish to remove (or hide, disable, etc.) the bottomViewController property, as its features have been replaced with other UI elements I created.
import SomeSDK
class MainViewController: DefaultLayoutViewController {
//Code for UI elements I created
}
The above code pulls all of the elements from the SDK's Class DefaultLayoutViewController, and builds my elements on top of it.
This property has this information about it in the documentation.
#property (nullable, nonatomic) SDKbottomViewController *bottomViewController
I have attempted to override from within the MainViewController class, but I am told 'Cannot override with a stored property'. How would I go about removing this inherited property from the class I am referencing? I obviously cannot simply delete the property from the initial class since I'm installing it in from an SDK Pod. I am newer to Swift, and coding in general, so perhaps I am just not wording my questions correctly in my research and failing to find an obvious solution that is documented out there. If this is repeated anywhere that I have missed, my apologies.
There is no way for a subclass to remove a property from a superclass. This violates the meaning of "inheritance." We usually refer to this as the Liskov Substitution Principle. There are various subtleties about how (and even if) this principle applies, but the way most programmers apply this is that anywhere DefaultLayoutViewController can be used, it is required that MainViewController also be usable. Consider this function:
func handleController(controller: DefaultLayoutViewController) {
doSomething(with: controller.bottomViewController)
}
If this were called with an instance of MainViewController, after you've "removed" bottomViewController, what should happen? This isn't a meaningful thing to do.
How you should handle this depends on exactly what you're trying to achieve. Generally the answer is "don't use class inheritance; use protocols." That may not be easy if you're tied to an existing class-based framework, but it doesn't change the fact that removing a property is not possible with inheritance.

Without exposing the interface in the public header of framework can I pass a custom object to the client application?

I am working with a objective-C framework.
I have a public framework header "MyPublicHeader.h" exposed to the client application. I have a custom class in the project,
//MyCustomClass.h file
#interface MyCustomClass.h
- (NSString *) methodA;
#end
//MyCustomClass.m file
#inplementation
- (NSString *) methodA {
}
#end
If I want the client to instantiate the class I have to make it as public framework header. I want to hide the interface as a curiosity, is there any way to do it???
First know that nothing can be truely hidden in Objective-C due to the nature of dynamic dispatch and the features in the runtime which allow discovery of methods etc.
That said there are a number of ways to do this, a couple:
Use a subclass. Declare a superclass and publish its interface as part of your framework. Make your class a subclass of this and publish its interface only within the framework. You define one or more init methods in the superclass which return and instance of the subclass, and if you want to expose any further API define it in the superclass with dummy (or faulting) implementations and less the subclass override etc. This approach is similar to the model used for classes like NSString.
A .h file is just text and you can exploit this: make two .h files, say MyCustomClass.h and InternalMyCustomClass.h. In the first just declare the interface with no members, or the API you wish to make public, and publish that to users of the framework. In the second declare the real interface used within the framework. You must make sure to keep all three of the files (2 .h, .m) in sync. This approach would be call little naughty by some, "here be dragons" by others, or "needs must" by yet others...
You might also like to look into "class extensions" which are related to categories.
Hope that satiates your curiosity a little, and keep up with the curiosity its good (except for cats)!
You could create an empty wrapper class which only holds a reference to your MyCustomClass object.
When they create this object you secretly instantiate an object of your MyCustomClass inside and extract it when they pass you an object of the wrapper class.
Not sure if this is exactly what you want to achieve, but could be a workaround.

ARC clarification: Will my class extension properties be released automatically?

I'm new to ARC, and I have little question I didn't find info about.
I'm writing communication class and I want to add properties to a 3rd party class.
I wrote this code in my communicationClass.h:
#interface AFHTTPRequestOperation()
#property (nonatomic, assign) id<TargetProtocol> delegate;
#property (nonatomic, assign) SEL callback;
#property (nonatomic, retain) NSString *requestIdentifier;
#property (nonatomic, assign) int authenticationMode;
#end
The properties are added fine and I use them. My question is,
will ARC release these properties even if AFHTTPRequestOperation
is extended in a different file (my communicationClass.h)?
You are adding your additional properties using a class extension (not a category). Class extensions can only be used when you have access to the original source code for the class being extended. In this case you presumably have the source code for AFNetworking included in your project.
Apple's Programming with Objective-C has this to say about class extensions:
A class extension bears some similarity to a category, but it can only
be added to a class for which you have the source code at compile time
(the class is compiled at the same time as the class extension). The
methods declared by a class extension are implemented in the
#implementation block for the original class so you can’t, for
example, declare a class extension on a framework class, such as a
Cocoa or Cocoa Touch class like NSString.
and
Unlike regular categories, a class extension can add its own
properties and instance variables to a class. If you declare a
property in a class extension, [...] the compiler will automatically
synthesize the relevant accessor methods, as well as an instance
variable, inside the primary class implementation.
This would suggest that properties added by a class extension will function exactly the same as they would if they were in the original implementation file. However, the documentation suggests that the class extension should be compiled at the same time as the original implementation, I'm not clear how this happens if the communicationClass.h is not included in the original AFHTTPRequestOperation.m implementation file.
Given that the properties are working for you I would have to assume that the Objective-C Runtime is recognising them and this likely means that ARC will work correctly.
It is probably worth testing this. To check that ARC correctly releases the property I would add some logging to the dealloc method of a class that you are storing in a property added using this method. If the dealloc gets called when the parent is destroyed then you'll know it is working.
Yes your extension will be dealt by ARC.
You are not required to worry about it.
And it would look good if you use weak and strong in #property
I would say "Yes", they will be managed for you, and this based on this blog article that talks about how properties are managed in categories using objc_setAssociatedObject(). At the end of the article the author states:
Note: When class object(UIView object) is deallocated, its property
(animationIdentifer) will be sent a -release message automatically.
So I am assuming that ARC would do this for you. It's not very authoritative, I know...
The question is, if the AFHTTPRequestOperation class is compiled with ARC support. When the answer ist yes, than the ARC will handle this. Otherwise, it will not and the answer is no.
Another thing is that retain should be strong when using ARC.

Why are there two #interfaces for view controllers?

I'm learning some Objective-C, specifically iOS-related stuff. Whenever I generate a new UIViewController, or UITableViewController, etc, both the generated .h and .m files contain an #interface. The application will continue to compile if I delete the #interface from the .m file, also. What is the purpose of this #interface in the .m file?
The #interface in the .m file is a class extension (a category with no name). It's now in the templates to let you put any declaration of internal methods or ivars you don't want to expose to other parts of the code.
With the advent of the modern Objective-C runtime and the progress of clang, a well written class should:
1) have only public methods in the header
2) have ivars and internal methods declared in the internal class extension
Technically, it is a "class extension" (see ("Extensions" section of) the Objective-C intro docs). In practice, it has become common to use this as a "private" interface (it is only "visible" to the file in which it exists). Objective-C does not stop anyone else from calling these methods, but they won't "see" them (think of the .h file as your public interface and this anonymous category as your private interface).
It is handy for declaring #propertys which you don't want to expose publicly.

xcode basic explanation needed

I am actually a newby at xcode. I can make out a few things be myself but have questions about what some things do and why they are put there. I have tried to read many e-books, watched tutorials, but they never go into the basics, alway just say "Add this, Click here etc"
Could someone give me some answers to a few questions please.
Ok, I know an ios app is mostly made out of Views, views are controlled by controllers. Each controller has a header (.h) file and a module?class? file (.m). The .h file contains the declarations of variables and functions used in the .m file.
The whole app is controlled by a master "controller" called the "delegate".
Definitions in .h file may be for example an action IBAction or IBLabel or something.
What raises questions for me is for example these lines:
#class FlipsideViewController;
#protocol FlipsideViewControllerDelegate
- (void)flipsideViewControllerDidFinish:(FlipsideViewController *)controller;
#end
#interface FlipsideViewController : UIViewController
#property (nonatomic, assign) id <FlipsideViewControllerDelegate> delegate;
- (IBAction)done:(id)sender;
and why are sometimes in another view controller the delegate class loaded
#class MainViewController;
what does the following do, meaning what is the #interface declaration?
#interface flipAppDelegate : NSObject <UIApplicationDelegate>
what is
nonatomic, retain
sorry for asking really stupid questions, but every tutorial just skips these things.
I can follow a youtube video or a manual, but it doesn't teach me a lot...
Let me try to answer your questions, one at a time.
what is the #interface declaration?
The interface declares a class. By declaring a class, I mean it specifies the instance variables and private/public methods that it contains. Again, the header file only contains the declaration of the methods, and the implementation/body of the methods lies in the module class. So, here-
#interface FlipsideViewController : UIViewController
The class FlipsideViewController derives from/subclasses/extends UIViewController. i.e Is a type of UIViewController but adds its own features.
Similarly
#interface flipAppDelegate : NSObject <UIApplicationDelegate>
Subclasses NSObject and implements the UIApplicationDelegate protocol. A protocol is essentially a set of methods that a class promises to implement (although there can be optional methods).
why are sometimes in another view controller the delegate class loaded
The delegate pattern allows a class to delegate its work to another class that implements the delegate protocol. So, here, FlipsideViewController keeps an instance of the delegate object, so that its flipsideViewControllerDidFinish: can be called.
what is nonatomic, retain
It means that when you set a value to your instance variable, the value's refcount will be incremented and set to your variable. Also, it will not happen as an atomic operation. You need atomic only in a multi-threaded environment.
#synthesize is simply a shortcut to generate getters and setters for your variables.
You really need to read the Objective-C Programming Language from Apple. It's pretty brief, and runs down the basics of the architecture, concepts, and syntax.
To address, briefly, some specifics:
The #class directive is used to declare the name of a class without importing it's header file. It is often used in a .h file declaring a protocol, because a protocol has no implementation, it doesn't need to import the interfaces of other classes (their .h files).
A protocol is a way of declaring what methods and properties a class should have in order to "implement" the protocol.
#interface is used in an interface file (.h) to declare a class, meaning to describe the methods and properties it will have, the protocols it will implement, and the superclasses from which it will inherit. In your example, the class will be called flipAppDelegate, which inherits all of the methods and properties of the NSObject class, and which implements the UIApplicationDelegate protocol.
In your class (.m) file, you will define (with all your code) all of the methods and properties that you declared in your interface file. You include the methods and properties you declared yourself, and from the protocols you implement.
#synthesize is used in a class implementation file (.m) to "synthesize" --- that is, automatically create the code for --- all the properties you declared in your interface (.h) file. Since properties normally just need basic accessors (a "getter" that just returns the current value, and a "setter" that just sets the current value), using #synthesize is a shortcut to let the compiler create the variable to store the value, the getter method, and the setter method for you automatically.
Xcode = An IDE (Integrated Development Environment)
Objective-C = A Language
Cocoa Touch, Media FrameWork, Core FrameWork = Frameworks used in developing for iOS
I'd highly recommend starting by learning Objective-C. At least with a primer first:
https://developer.apple.com/library/ios/#referencelibrary/GettingStarted/Learning_Objective-C_A_Primer/_index.html
There's a wealth of tutorials and videos available from Apple for developers you might want to start on the developer portal.

Resources