What is get used for in Swift? - ios

Code: https://github.com/acani/Chats/blob/master/Chats/Chats/ChatViewController.swift
The inputAccessoryView method uses get { }. Any reason why?
If I put a "println" on the line before get, it says use of unresolved identifier 'get'. I'm trying to see if the code before get is being called because the println I have inside is not being called.
What exactly is get used for here?

See Properties in the reference. Scroll down to "Computed Properties".
In addition to stored properties, classes, structures, and enumerations can define computed properties, which do not actually store a value. Instead, they provide a getter and an optional setter to retrieve and set other properties and values indirectly.
So that syntax lets the value returned by a property to be caluclated on the value rather than just fetching a value. Code other than a get or set block in a property definition is not valid, which is why you get that error.

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.

How to pass reference types by value?

I just started a question a few minutes ago were I learned, that class instances in swift are reference types. However as I asked how to pass an instance as copy then or just make a copy inside a function nobody seems to know for sure. So my question is:
Is it possible to pass a class object to a function by value?
If yes, how to do so and if no, how can I work with a copy then?
It is not possible to pass class objects in Swift by value. What is more, there is no general way of making copies of objects, so you need to provide e.g. appropriate initialiser yourself.
Value objects and reference objects serve different purposes. Asking how to pass a reference object by value is just absolutely pointless. However, a lot of the time you will pass immutable objects, and that means the reference to the object is the value.
By the way: You don't mean "class objects". You mean "instances of a class". In Objective-C, classes are themselves objects. For example, you send the alloc message to a class object.
How to pass reference types by value?
The answer to this question as phrased is you just pass it, by value. It works the exact same way for reference types and value types. Any parameter that is not marked inout in Swift is pass-by-value.
The value of a reference type variable is a reference, which points to an object. When you pass a reference by value, the receiving function receives a copy of this reference, which points to the same object.
Upon further reading of your question, it appears that you are not asking about the passing of reference types at all. Rather, you are asking about the copying of objects. When you wrote "reference type" what you really meant is something like an "object type", something whose value is an object, which when passed by value results in a copy of the object.
Swift has no "object types"; just like Objective-C and Java do not have "object types". It's impossible to have a variable whose value "is an object"; you can only have a variable whose value is a reference that "points to an object". You manipulate objects through these references. There is no syntax in the language to "dereference" a reference to the object it points to.

Key Value Coding clarification

From Apple's documentation I came across the following:
Setting values using key paths is not the same as setting them using
Objective-C properties. You cannot use property notation to set
transform values. You must use the setValue:forKeyPath: method with
the preceding key path strings.
From my understanding, we must have properties of our ivars in order to use KVC.
But from the paragraph above, it seems to say otherwise:
Setting values using key paths is not the same as setting them using
Objective-C properties. You cannot use property notation to set
transform values.
Can someone explain to me why? Perhaps I am missing something, because all along my understanding is that we must have properties to utilize KVC.
From my understanding, we must have properties of our ivars in order to use KVC.
This is incorrect. KVC will use the property generated accessor methods, or other (appropriately named) accessor methods if they exist, but they aren't required. If they don't exist KVC will attempt to directly access the instance variables.
Check this Apple ref for a description of how KVC searches for the key to update.

ARC and sending messages to objects without specifying the class at compile time

I'm trying to understand where ARC is getting the method signature information to do its job.
In the following code, I send a message to the parent of this object without specifying its class.
If I don't typecast the parent ivar, the compiler issues a warning.
If I typecast it to id, then the program works and no warnings are issued. The same is true
if I use performSelector:withObject:
If the method on the parent is different to userSelected: then the only thing that works
is performSelector (while issuing a warning).
As I understand it, ARC is getting the method signature from the object the call to self.parent is made. Is this correct? Can you avoid telling ARC what class an object is if the method signature exists in the object from which the message is being sent?
- (void)userSelected:(id)sender
{
if ([self.parent respondsToSelector:#selector(userSelected:)]) {
//1: This fails with error (no visible interface).
[self.parent userSelected:self];
//2: This line works without warnings.
[(id)self.parent userSelected:self];
//3: This line also works
[self.parent performSelector:#selector(userSelected:)
withObject:self];
}
Wil Shipley is correct in his deleted answer when saying that this is not ARC related.
The warning you are getting is about the static type of the receiver (self.parent) and the compiler trying to help you to prevent sending messages to an object that doesn't respond to this selector. In other words: self.parent's class does not contain a declaration of userSelected:.
But the compiler does know a method named userSelected: (in some other class or category) because it lets you send this message to an object without static type information. It's a little like the C language lets you use a void pointer for any type of pointer.
So, again, all of that is not ARC related and would not change when switching to MRC.
Edit:
Yes, when sending messages to id the compiler considers any visible #interface and #protocol to find the selector's declaration. "Visible" in this case means any imported header, be it custom, framework or prefix. The method declaration is needed mainly to get type information of the parameters.
Note that ARC behavior is only affected in very rare scenarios (when the declaration includes information about ownership semantics, like objc_method_family and similar).
If the compiler finds conflicting declarations it emits an error. When trying to compile ...
[(id)nil type];
... you'll get ...
> error: multiple methods named 'type' found with mismatched result, parameter type or attributes
... plus a couple of differing declarations in UIKit, Foundation and other frameworks.

KVC and accessor methods

I have a understanding problem with one aspect of KVC and accessor method.
When I access my getter/setter methods with self.variable/self.setVariable the method observeValueForKeyPath:ofObject:change:context: gets executed
But if I understand apples documentation correctly from here
[...] and then uses setValue:forKey: to set the new value. This
maintains encapsulation of the model and ensures that any additional
actions that should occur as a result of setting the value will
actually occur. This is considered better practice than calling an
accessor method or setting an instance variable directly.
it should not get executed.
Is there something else that gets executed when I use setValue:forKey: which is not getting executed when I use the getter/setter methods?
What is getting executed when I use setValue:forKey: which isn't executed when I use the accessor methods?
Code example here

Resources