In NSArray.h I saw the interface like this
#interface NSArray<ObjectType>
What is the significance of <ObjectType>?
That is Apple using lightweight generics. The full #interface declaration in Xcode 7.3.1 looks like this:
#interface NSArray<__covariant ObjectType> : NSObject <NSCopying, NSMutableCopying, NSSecureCoding, NSFastEnumeration>
ObjectType is a placeholder used to represent the generic argument you pass into so that the compiler knows where to reference them. This is different than using NSObject * because ObjectType is like id, it can refer to non-Objective-C pointer types such as CoreFoundation objects.
For example, if I wanted to create a class that mocks an array for only a specific class, I could do something like #interface MYArray<MyClass *>.
You could also specifically declare an array of strings as NSArray<NSString *>.
See this article on Objective-C Generics for more information.
Related
I have two classes, Entity, and EntityHandler.
EntityHandler has a method, AddEntity. This method adds the Entity to an NSMutableArray.
Entity has a method called subscribe. It assigns a reference to EntityHandler to a variable for later usage.
Upon the inclusion of both header files in each other the project breaks. For example,
-(void) addEntity: (Entity *) mob;
returns the error
Expected a type
How can I fix this?
You're looking to employ forward declarations for your ObjC types, in order to break the cyclic header dependency.
It would look something like:
// EntityHandler.h
#class Entity; // << the forward declaration. not #import.
#interface EntityHandler : NSObject
-(void) addEntity:(Entity *) mob;
#end
This tells the compiler that there is an ObjC class named Entity.
Then you #import when you need more than a typename (likely in EntityHandler.m).
I have class A, which exposes a way of getting and setting an object of type Foo. In property parlance, I generally declare this in the interface:
#property (nonatomic, strong) Foo * foo;
This (in modern ObjC) generates both the accessors and an ivar, _foo for storage.
If I want to do custom work in the accessors, I can implement one or both of them myself. But what if I not only want to do custom work, I actually don't want the ivar? In other words, I'm doing something else with the Foo object, like handing it back and forth to another internal object that I'm composed with. I don't actually need to keep storage for foo in the instance of A at all.
It seems like I have two choices:
Declare the property, implement both accessors, and simply ignore the fact that the compiler creates storage for _foo, and never use it.
Declare my accessors explicitly: - (Foo *)foo and - (void)setFoo:(Foo *)foo in the interface, like I used to in pre-modern ObjC.
The first seems inelegant at runtime, and the second seems inelegant in the declaration (where I'd probably now have a mix of properties and property-like accessors).
Is there a way to declare a property and have it serve as purely a declaration?
Use the #dynamic keyword in the implementation file. The usual discussion of #dynamic describes it as not creating the accessors at compile time. Not usually mentioned is that is also has the effect of doing nothing to create storage for the property, which is exactly what is desirable in this case.
#implementation A
#dynamic foo;
- (Foo *)foo
{
// get a Foo from somewhere and return it.
}
- (void)setFoo:(Foo *)foo
{
// do something with foo
}
#end
(Note: answered my own question since I discovered this while writing up the question and it seemed interesting and nonobvious.)
If you override both the setter and getter and don't use the variable within the setter and getter, a variable will not be created.
For example, if you have a class for which you want a firstName and lastName property, but perhaps also a setter and getter for a fullName property, if your fullName setter simply parses a string into firstName and lastName and sets these properties to that (and never stores the full string into a fullName variable), and your fullName getter simply returns the concatenated firstName + lastName and never uses a fullName variable, one will never be created.
This is according to Apple's official documentation. Scroll down to "You Can Implement Custom Accessor Methods"
#dynamic is probably the way to go.
However, there are two other ways you can do this as well:
An Unimplemented Category
You can use an un-implemented category to declare a property, but not get the backing storage:
#interface Foo : NSObject
#end
#interface Foo (UnimplementedProperties)
#property (strong) id bar;
#end
#implementation Foo
#end
By not declaring the implementation of the category (#implementation Foo (UnimplementedProperties)), the properties won't be synthesized.
A Protocol
You can declare the properties on a protocol, and then make your class conform to that protocol. This has the same effect as the unimplemented category: the methods are declared, but the properties are not synthesized.
#protocol FooProperties <NSObject>
#property (strong) id bar;
#end
#interface Foo : NSObject <FooProperties>
#end
I created two classes in objective c and I would like to use one of them as a property of the other. To be more concrete, one of the classes is a 'term' that contains an integer variable and an nsstring that acts as the variable. The other class is an 'expression' that has an nsmutable array as an instance variable that contains 'terms' as its objects. What I want to do is have add the possibility of having one of the terms have an 'expression' as a property to implement something like distributing over parentheses and substituting an expression for a variable. However, Xcode is telling me that 'expression' is not an acceptable type name despite the fact that I have imported my expression header file. I think I may have read somewhere that only foundation classes are available to use as properties. What can I do to add this class as an instance variable?
I suspect you have an import cycle, like this:
Expression.h
#import "Term.h"
#interface Expression : NSObject
...
Term.h
#import "Expression.h"
#interface Term : NSObject
...
Notice how each file imports the other? That won't work. Instead, you need to use forward declarations:
Expression.h
#class Term; // tell the compiler that Term is a class name
#interface Expression : NSObject
...
Term.h
#class Expression; // tell the compiler that Expression is a class name
#interface Term : NSObject
...
Then, in your .m files, you can safely import both .h files:
Expression.m
#import "Expression.h"
#import "Term.h"
#implementation Expression
...
Term.m
#import "Term.h"
#import "Expression.h"
#implementation Term
...
Although the above answers are also correct, in my case the problem which occured was "#end" was missing in prototype/interface declaration.
A class can be extended in Objective C using a category such as:
#interface NSString (CategoryName)
-(NSString *)myFabulousAddition; // a fabulous additional method
#end
/////////////////////////////
#implementation NSString (CategoryName)
-(NSString *)myFabulousAddition {
// do something fabulous...
}
#end
In this small example, I would be adding the method myFabulousAddition to NSString. I could then call it by [anNSString myFabulousAddition] just as if it were part of the NSString set of methods. Great and useful.
In the Apple documents regarding Categories, the docs state:
There’s no limit to the number of
categories that you can add to a
class, but each category name must be
different, and each should declare and
define a different set of methods.
What if you have something like this:
#interface NSString (CategoryName)
-(NSString *)myFabulousAddition; // a fabulous additional method
#end
#interface NSString (ANOTHERCategoryName)
-(NSString *)myFabulousAddition; // a DIFFERENT fabulous additional method
// BUT with same name as the other category
#end
/////////////////////////////
#implementation NSString (CategoryName)
-(NSString *)myFabulousAddition {
// do something fabulous...
}
#end
#implementation NSString (ANOTHERCategoryName)
-(NSString *)myFabulousAddition {
// do something equally fabulous, but DIFFERENT...
}
#end
The lack of a name in the parenthesis indicates that the form is an extension to the class, like so:
#interface MyObject () // No name -- an extension vs category to MyObject
- (void)setNumber:(NSNumber *)newNumber;
#end
Does the category name have any meaning to the compiler or linker? Is the category name part of the method signature in anyway or is it part of a primitive namespace? If the category name is meaningless, how do you know if you are about to stomp on another method and get undefined behavior?
The way to avoid stomping on methods is to prefix your category method names, like this:
#interface NSString (MyCompanyCategoryName)
- (NSString *)MYCO_fabulousAddition;
#end
If you get a collision of method names from different categories, then which one 'wins' at run time is completely undefined.
The name of a category is almost entirely useless, with the exception being that the nameless category (i.e. ()) is reserved for class extensions. Methods from class extensions are supposed to be implemented in the class' main #implementation.
The category name doesn't mean anything special, it's just an identifier. Unless the linker (or runtime loader) decides to give you a warning, there is no way to tell that multiple categories are defining the same method.
The behavior is (largely) unpredictable - one of the categories will win out, but you can't tell which one. Also, I think it's well possible you will start out with one implementation and end up with another one (if the second category is loaded after the first).
It certainly acts as an identifier, from the programmer's point of view. In the compiler point of view category methods are simply added as an extension of the class ( from which it is extending), regardless of the name.
And yes you can add categories of the same class with the same identifiers, even with same functions. But you definitely can't override any function because categories are just part of the class once you define them ( Just like you can't override a function of a class from within that class ).
As they are being added at runtime, they don't raise any error and only at runtime compiler selects the function, which is totally unpredictable.
i believe that they don't have any meaning. You don't really use them in your code ... Since they are categories and ... the semantic of a category ... is just to categorize something, i think this is somewhat logical ...
I would say they just simply gather the methods ...
On the other hand your question is very valid ... You DON'T KNOW if you override a method. If you are in the same project then the compiler issues a warning (or an error ? i don't remember), however if you are overriding a method from a library, then .. you are out of luck ...
is it possible to specify that a NSMutableArray can only contain a certain type of objects.
For example, if I want to store only this kind of objects :
#interface MyObject : NSObject {
UInt8 value;
}
In order to be able to use the instance variable like this :
- (void)myMethod:(NSMutableArray *)myArray{
for (id myObject in myArray){
[self otherMethod:myObject.value];
}
}
because I'm getting this error :
request for member 'value' in something not a structure or union
Thank you for your help
It sounds like you're coming from a Java/C# type background where limits can be imposed on collections.
Collections in Cocoa don't follow that pattern. There is no way to set a restriction on what type of objects can be inserted (unless you write a wrapper class that enforces this).
Objective-C, by design, follows the "if it walks like a duck and it quacks like a duck, then it most probably is a duck" philosophy. That is to say that rather than checking whether an object is a particular type, you should be checking whether it can do what you want it to do regardless of its type.
You can do this using respondsToSelector:.
Finally, your problem isn't actually related to the fact that the array has no restrictions. Your object doesn't appear to declare the instance variable value as a property, or expose any accessor methods for it.
This is why you're seeing the error when you try myObject.value. That syntax in Objective-C is how you access properties.
The default scope for instance variables in Objective-C is #protected, which means anything outside your class can't access them without going through an accessor method of some kind.
You need to declare and define the methods - (UInt8)value and - (void)setValue:(UInt8)aValue and use them.
Alternatively, you could declare it as a property.
You are getting that error, because for as far as Objective-C is concerned, myObject is of the non-type id, which doesn't support the value property. To make Objective-C aware of the fact it's always dealing with a MyObject in this loop, you'll have to tell it the myObject object is an instance of MyObject.
for (MyObject *myObject in myArray) {
Also, you have to make sure the value ivar is accessible using dot-notation by implementing getter and setter methods for it. You can do this yourself by implementing -value and -setValue:, or you can use #property and #synthesize to let Objective-C do this.
Objective-C doesn't work like that. You need to use [myObject value] (which will work irrespective of the kind of object, as long as it responds to -[value]. If you only want one type of objects in it, insert only that type of objects.
You would have to write a wrapper-class for the NSMutableArray, see for example this question.
Subclass NSMutableArray and override methods that mediate the addition of objects to the array. You would check the object type in these overridden methods, only calling [super addObject:xyz] if the type is accepted.
maybe you can use protocol:
#protocol Person <NSObject>
#end
#interface Person : NSObject <Person>
#end
to use:
NSArray<Person>* personArray;