id<> required for MTLDevice class - ios

I am very new to Objective-c so bear with me I am still trying to make sense of the multitude of places you can put properties and class variables in objective c.
I am an experienced Metal developer but I have barely done anything with objective-c.
I am trying to create a MetalCore class that will hold the MTLDevice, MTLCommandQueue and facilitate the creation of the apps core pipelines etc.
I therefore defined the following
#property (readonly, nonatomic, assign) MTLDevice* devicePtr;
In my class however I get the error Unknown type name MTLDevice; did you mean... even though I #import <Metal/Metal.h> so what is going on here?
I looked on stack overflow and found examples where people were defining function like this
- (<MTLDevice> *)device;
or
- (instancetype)initWithDevice:(id<MTLDevice>) device;
What is going on with this whole id and <> thing? In what cases can you omit the id part?
What I find especially weird is while id seems to be required for most Metal types there are some like MTLRenderPipelineDescriptor that dont need it and in fact only work in the Type* mode. Why is this and how do I determine what is needed from the documentation?

In Objective-C, id basically means "any object type". If you want to ensure that an object conforms to a protocol (such as MTLDevice), you specify the protocol in angle brackets after id when stating its type: id<MTLDevice> means "a type that conforms to the MTLDevice protocol".
Unlike with concrete classes (such as MTLRenderPipelineDescriptor), you don't use a * after id, so you wouldn't write id<MTLDevice> * (unless you were taking a pointer to a device, which is uncommon). MTLDevice * doesn't make sense because MTLDevice isn't a concrete type. <MTLDevice> by itself is nonsense, and a syntax error, as is <MTLDevice> *.
Coming from Swift, you might be used to conflating between protocols and concrete types, since Swift doesn't make a syntactic distinction between "some type that conforms to a protocol" and "some concrete type." To tell whether something is a protocol, consult the documentation; it'll explicitly note when something is a protocol. In Metal, all "descriptor" types are concrete (e.g., MTLRenderPipelineDescriptor), while most other object types are abstracted behind protocols (MTLDevice, MTLCommandQueue, MTLLibrary, MTLFunction, MTLTexture, MTLRenderPipelineState, MTLCommandBuffer, etc.)

If you know java ,id<MTLDevice> is like a object that inherited the Interface named ‘MTLDevice’.
Mainly due to different iPhone has different GPU architectures. For the maximum efficiency,different GPU has different implementation of metal.
Such as in iPhoneX the real MTLDevice is a class named 'AGXA11Device' , while in iPhone 6 plus is 'AGXA9Device'.

Related

How "id" type understands the receiver of method without casting?

After merging master to my working branch I got compiler error on the line, which wasn't be changed. The error looks like
id test;
[test count];
Multiple methods named 'count' found with mismatched result.
At first it looks clear, because compiler doesn't know which concrete type the "test" variable is. But I don't understand why it worked before.
If I create a new file this line works, assuming that is a NSArray's method. Why compiler doesn't show error in this case?
While showing error message, there is several possible receivers of count method are shown. (NSArray, NSDictionary, NSSet) Does it search all classes that can receive that message and show error if there are multiple?
I noticed that error occurs when I import "-Swift.h" file. How it depends?
Compiler doesn't cast or check your id type. It just provides you all possible selectors. You said that this issue connected with importing "-Swift.h" file. In this case check you Swift code, probably you have count function visible for Objective C which returns something else than Int.
Also, you can check the issue in Issue navigator, select it and it will show all count calls visible in Objective C. Check them all, most of them will return NSUInteger, but there should be one that returns something else, for example:
SWIFT_CLASS("_TtC3dev19YourClass")
#interface YourClass : NSObject
- (int32_t)count SWIFT_WARN_UNUSED_RESULT;
#end
Objective-C doesn't need to know the type of the receiver. At run-time, all objects are just id, and everything is dynamically dispatched. So any message can be sent to any object, no matter its type. (At run-time, objects are free to decide what to do with messages they don't understand. The most common thing to do is raise an exception and crash, but there are many kinds of objects that can handle arbitrary messages that don't map directly to method calls.)
There is a couple of technical details, however, that complicate this.
The ABI (application binary interface) defines different mechanisms for returning certain primitive types. As long as the value is "a word-sized integer," then it doesn't matter (this includes things like NSInteger and all pointers, which means by extension all objects). But on some processors, floats are returned in different registers than integers, and structs (like CGRect) might be returned in a variety of ways depending on their size. In order to write the necessary assembly language, the compiler has to know what kind of return value it will be.
ARC has added additional wrinkles that require that the compiler know a more about the type of the parameters (specifically whether they're objects or primitives), and whether there are any memory-management attributes that have to be considered.
The compiler doesn't really care what "real" type test is, as long as it can figure out the types and attributes of -count. So when dealing with an id value, it looks through every known selector it can see (i.e. every one defined in an included header or the current .m). It's fine if there are many of them on different classes, as long as they all agree. But if it can't find the selector at all, or if some of the interfaces disagree, then it can't compile the line of code.
As lobstah notes, you likely have a type somewhere in your Swift code that has an #objc method called count() or an #objc property named count that returns something other than Int (which maps to NSInteger, and so match the usual signature of -count). You'll need to fix that method, or you'll need to hide it from ObjC (for example, by adding #nonobjc).
Or much better: get rid of the id, and use its actual type. id is generally a bad idea in Cocoa, and is especially a bad idea if you're calling methods on it, since the compiler can't check that the object will respond and you may crash.

Cannot assign a value of type 'AnyDataSource<NSManagedObjectSubclass>' to a value of type 'AnyDataSource<NSManagedObject>'

I'm stumped.
The title of this question the compiler error.
I am creating an object that basically marries the delegates of NSFetchedResultsController and UITableViewDataSource. The type parameter is used to indicate which NSManagedObject subclass should be used in the fetch requests.
Here is an example where Swift lacks dynamism and we end up writing all sorts of crazy code, (OR, I'm new to Swift and dislike being told what I'm not allowed to do)
So, on a UITableViewController subclass, i'd like to have a property
var dataSource: AnyDataSource<NSManagedObject>?
when I try to create one of these with a subclass of NSManagedObject and assign it to that property, the compiler complains. There seems to be nothing I can do that will succeed without a warning.
You would think that I should be able to use NSManagedObject or any of its subclasses, so I'm a little confused.
Any ideas? I'm using typical "type erasure" patterns that can be found on the internet, like via realm.io.
Ultimately I found that this approach was not possible. I mean, to achieve these with completely protocol-based programming.
I defined a few base protocols with no associated type, implemented an abstract baseclass that implements that protocol, then introduced generic type parameters in subclasses, that implement further protocols that have associated type.
I'll post my generalized solution on github when it's finished.

Meaning of the angle brackets in Objective-C?

Even though the question is quite wide I am actually curious regarding one case I sow recently while using the Realm library. As I previously used the protocols(delegate) on many occasions and also imported classes using <>. And now this is the line the code I don't completely understand or don't understand at all if I am mistaking:
#property (nonatomic, strong) RLMArray <ExerciseLog *><ExerciseLog> * exerciseLogs;
I suppose that the second part of the line <ExerciseLog> * exerciseLogs is used to ensure that exerciseLogs may be an instance of any ExerciseLog that conforms to the ExerciseLog protocol, is my assumption correct?
Or simple said if the user send a different object then the expected one, the app won't crash, and that a default value will be assigned.
And this part I am guessing, the is some sort of safe casting so that the returned object confirms to the ExerciseLog.
A combination of Obj-C protocol conformance and generics. RLMArray is declared as
#interface RLMArray < RLMObjectType : RLMObject * > : NSObject<RLMCollection,NSFastEnumeration>
it has one generic argument. That's the <ExerciseLog *>.
The second part <ExerciseLog> is conformance to protocol of the given type.
By the way, that protocol is declared using RLM_ARRAY_TYPE macro. The code seems to be a bit complicated but it was probably an older way to enforce element type for arrays (RLMArray<protocolX> is not assignable to RLMArray<protocolY>).
Quoting the documentation:
Unlike an NSArray, RLMArrays hold a single type, specified by the objectClassName property. This is referred to in these docs as the “type” of the array.
When declaring an RLMArray property, the type must be marked as conforming to a protocol by the same name as the objects it should contain (see the RLM_ARRAY_TYPE macro). RLMArray properties can also use Objective-C generics if available. For example:
The angle brackets in a class interface definition indicates the protocols that your class is conforming to.
A protocol is almost like an interface in Java or C#, with the addition that methods in an Objective-C protocol can be optional.
Additionaly in Objective-C you can declare a variable, argument or instance variable to conform to several protocols as well. Example
NSObject *myVariable;
In this case the class must be NSObject or a subclass (only NSProxy and its subclasses would fail), and it must also conform to both NSCoding and UITableViewDelegate protocols.
In Java or C# this would only be possible by actually declaring said class.

Casting method parameters in Objective-C

Update
Okay, first of all, thank you all for the huge amount of activity. It seems that I did not phrase my question too well, since many of the answers got (rightfully) stuck on the id input parameter, and following poor design patterns, but it was merely an example. I'll add some context to my question:
Suppose that there are multiple different implementations for doSomethingWithParameter:, requiring a specific instance as input parameter
My class in the example will only ever get called with an instance of SpecificClass as input parameter
With these assertions, here is my assumption: Given, that you know the type of the parameter, there is no benefit in type checking and casting, just for the sake of extra safety.
Original post
Suppose I have a general method in my protocol declaration, which takes an id input parameter:
#protocol MyProtocol <NSObject>
- (void)doSomethingWithParameter:(id)inputParameter;
#end
In a class, which conforms to MyProtocol, I usually prefer making the type of inputParameter explicit like so:
- (void)doSomethingWithParameter:(SpecificClass *)inputParameter
{
/... do something with param
}
Occasionally I received critique for choosing this solution, as opposed to the following:
- (void)doSomethingWithParameter:(id)inputParameter
{
if ([inputParameter isKindOfClass:[SpecificClass class]]) {
SpecificClass *myInstance = (SpecificClass *)inputParameter;
/... do something with param
}
}
I really prefer the first version, since it clearly states the parameter my instance is expecting. It is more concise, and clear. I generally don't think I can gain much from type checking/casting.
My question: from a coding standard standpoint, which one is the better solution? Does the first one have any disadvantages?
Update
From the update to your question, it seems that you are trying to achieve some variation of a functionality provided by the generics in modern languages.
Since Objective-C does not support this pattern, you can either sacrifice type safety, or rethink your design decisions.
If you go the first way, you should make it really clear by other means (naming, documentation) what types are you expecting. Then it might be reasonable to assume that your method will only be called with proper params.
But I would still add NSParameterAssert to simplify future debugging.
Original Answer
If you are using the first approach, you have a mismatch between declaration and definition of the method. Due to dynamic nature of obj-c (method signature does not include types of parameters), compiler does not complain about it.
However, when calling the method, only declaration is visible, so any information about the type of parameters is derived from that - all the type checking (yes, here compiler does it) is performed based on declaration.
In conclusion, to avoid confusing bugs and misuse of API, you should definitely use the second approach. Or change declaration together with definition.
Edit
Also, I can think of third solution, that somewhat merges convenience of the first approach with type safety of the second one:
- (void)doSomethingWithParameter:(SpecificClass *)inputParameter
{
NSParameterAssert([inputParameter isKindOfClass:[SpecificClass class]]);
// do something
}
First of all, when you use id for a parameter type that means either that type may vary or you may invoke method with ambiguous parameter. For both cases, second one is preferred as it checks type and prevents unwanted crash.
If you prefer the type of inputParameter explicit then simply define it in the protocol, like
#protocol MyProtocol <NSObject>
- (void)doSomethingWithParameter:(SpecificClass *)inputParameter;
#end
and for this forward declaration you may have to import module/class, like
#import "SpecificClass.h" // import class
OR
#class SpecificClass; // import module
What you do is perfectly fine. If your method is called with a parameter that is an instance of the wrong class, that is a bug in the caller. In Objective-C, you don't work around bugs, you make them crash your code, and then you fix the bug (that is why nobody handles exceptions, exceptions are bugs in your code and when they crash your code, the cause of the exception needs to be fixed).
This is much more common when you pass blocks, for example a block testing array elements, where you know exactly what type of array to expect.

Property or not property?

Quick question about semantics :)
If I was writing a protocol, which is preferred:
// (a)
#protocol MyProtocol
#property (nonatomic, copy) NSSet *things;
#end
vs.
// (b)
#protocol MyProtocol
- (NSSet *)things;
- (void)setThings:(NSSet *)things;
#end
(a) is cleaner code but has the implication that implementing classes will have an ivar for things, which isn't the case in my project. Because of my use case, things cannot be KVO either. It also implies that the implementing class will copy things, which it's not doing in every case for me.
(b) is more accurate code (it's very explicit about what you can / can't do i.e. no KVO) but it's a little messier.
Any opinions?
I am amending my answer that (a) probably is not best for a protocol but best for a non-protocol interface.
I would go with the #property. How a property is implemented is an implementation detail and I never consider that from the outside.
Consider a v1 implementation where the property is only that. In v2 the internals are changed and either the setter or getter is made a method. Totally reasonable, one of the reasons that properties are good, they allow such changes, they hide the implementation details.
Also consider the opposite, in the next version where is is desired to remove the methods and replace them with a property. Again an implementation detail that a property in the first instance covers quite well.
Finally, in this case there is a copy attribute which provided explicit information of how a call with a mutable object will be handled, that is lost in the method implementation.
Protocols define messaging contracts [1]. They are not intended to store data. According to the Apple documentation you are only supposed to add properties to class extensions (you can add properties to categories but the compiler won't synthesize an ivar) [2]. Depending on what you are trying to do I would use one of the two following approaches to be consistent with the documented usage of the Objective-C language:
If you have the source code of the class (its one you created) then use a class extension.
If you do not have the source code sub-class the object.
That being said, if you really need to do it the other way use option (b). It is more corect and more correct is cleaner code!
Here is another question that deals with the same issue.
Good luck
I think case 'a' makes misinformation: class adopting protocol MyProtocol can follow not rules nonatomic and copy.
And for me it's very odd add properties inside protocols. It is going against paradigms of object oriented programming: delegates shold do some action, not provide informations.
So I advice you not use 'a' and 'b' cases, but to think again about yours programm architecture.

Resources