Skip to content

Commit

Permalink
General updates 2
Browse files Browse the repository at this point in the history
  • Loading branch information
sashakid committed Oct 9, 2017
1 parent 661402b commit a5e1067
Show file tree
Hide file tree
Showing 7 changed files with 168 additions and 15 deletions.
Binary file added Images/responder_chain_in_action.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
61 changes: 58 additions & 3 deletions Main/11_runtime.md
Original file line number Diff line number Diff line change
Expand Up @@ -147,9 +147,40 @@ struct point {

<a name="тип-id"></a>
## Тип id
1. Что случится во время компиляции если мы посылаем сообщение объекту типа id?
2. Что случится во время выполнения если этот метод существует?
3. Что произойдет здесь?

__id__

```c
typedef struct objc_class *Class;
typedef struct objc_object {
Class isa;
} *id;
```
`id` is a pointer to any Objective-C object (`objc_object`). It is not just a `void` pointer and you should not treat it as so. It references an object that should have a valid `isa` pointer. The values that can be stored in `id` are also not just limited to `NSObject` and its descendants, which starts to make sense of the existence of the `NSObject` protocol as well as the `NSProxy` class which does not even inherit from `NSObject`. The compiler will allow you to assign an object referenced by type `id` to any object type, assign any object type to `id`, as well as send it any message (that the compiler has seen) without warning.

Thus “id” type is polymorphic. This is very powerful as it doesn’t require a cast to use such a value:
```objectivec
id data = ...;
NSString *host = [data host]; // assume NSURL
```
Sure enough `id` usage can lead to bugs, because the availability of the method is determined at runtime. This is called “dynamic (or late) binding”. Nevertheless if used carefully it is very useful and lets you write parts of the code faster as if using a scripting language.

Unfortunately this doesn’t work with property syntax:
```objectivec
id data = ...;
NSString *host = data.host; // error: "Property 'host' not found"
data.host = @"dobegin.com"; // same error
```

__instancetype__

> Use the `instancetype` keyword as the return type of methods that return an instance of the class they are called on (or a subclass of that class). These methods include `alloc`, `init`, and class factory methods. Using `instancetype` instead of `id` in appropriate places improves type safety in your Objective-C code.
* Что случится во время компиляции если мы посылаем сообщение объекту типа id?

With a variable typed `id`, you can send it any known message and the compiler will not complain. With a variable typed `NSObject *`, you can only send it messages declared by `NSObject` (not methods of any subclass) or else it will generate a warning.

* Что произойдет здесь?
```objectivec
NSString *s = [NSNumber numberWithInt:3];
int i = [s intValue];
Expand All @@ -159,3 +190,27 @@ int i = [s intValue];
MyArray *array = [MyArray arrayWithObjects:@(1), @(2), nil];
```
Теперь вы видите, почему возвращаемый тип `arrayWithObjects:` должен быть `id`. Если бы это был `(NSArray *)`, то подклассы потребует, чтобы они были приведены к необходимому классу.

* В чем разница между `void` и `void *`?

The `void` type, in several programming languages derived from C and Algol68, is the type for the result of a function that returns normally, but does not provide a result value to its caller. Usually such functions are called for their side effects, such as performing some task or writing to their output parameters.
C and C++ also support the pointer to `void` type (specified as `void *`), but this is an unrelated notion. Variables of this type are pointers to data of an unspecified type, so in this context (but not the others) `void *` acts roughly like a universal or top type. A program can probably convert a pointer to any type of data (except a function pointer) to a pointer to `void` and back to the original type without losing information, which makes these pointers useful for polymorphic functions. The C language standard does not guarantee that the different pointer types have the same size.

In C and C++

A function with `void` result type ends either by reaching the end of the function or by executing a return statement with no returned value. The `void` type may also appear as the sole argument of a function prototype to indicate that the function takes no arguments. Note that despite the name, in all of these situations, the `void` type serves as a unit type, not as a zero or bottom type (which is sometimes confusingly is also called the "void type"), even though unlike a real unit type which is a singleton, the `void` type lacks a way to represent it's a value and the language does not provide any way to declare an object or represent a value with type `void`.

* Можно ли создать структуру и привести к id?

`NSValue`

> A simple container for a single C or Objective-C data item. An `NSValue` object can hold any of the scalar types such as `int`, `float`, and `char`, as well as pointers, structures, and object `id` references. Use this class to work with such data types in collections (such as `NSArray` and `NSSet`), Key-value coding, and other APIs that require Objective-C objects. `NSValue` objects are always immutable.
```objectivec
[NSValue valueWithBytes:&struct objCType:@encode(MyStruct)];
```
And to get the value back out:
```objectivec
MyStruct struct;
[value getValue:&struct];
```
88 changes: 88 additions & 0 deletions Main/19_general_questions.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@
- [Как работает KVO и какие могут быть с ним проблемы?](#kvo)
- [Как изменятся свойства, если применить поворот на 45º?](#rotate-view)
- [Отличие view от layer?](#view-layer-difference)
- [Как передвинуть все subviews?](#moving-subviews)
- [Swift optionals, Objective-C new modifiers (`nullable`, etc.). что это и как реализовано?](#optionals-swift-objc)

<a name="общие-вопросы-и-задачи"></a>
# Общие вопросы и задачи
Expand Down Expand Up @@ -810,3 +812,89 @@ Views
- Can receive touch events
- Are always backed by a Layer on iOS
- No implicit animations
<a name="moving-subviews"></a>
## Как передвинуть все subviews?
You're talking about two different coordinate systems. `mainView.center` is expressed in the coordinate system of the view that contains `mainView`, whereas `firstView.center` and `secondView.center` are in terms of the coordinate system of `mainView`. You can certainly move `firstView` and `secondView` together by moving the view that contains them, but you need to translate between those two coordinate systems if you want to get the same result that you get by moving the two views themselves.
<a name="optionals-swift-objc"></a>
## Swift optionals, Objective-C new modifiers (`nullable`, etc.). что это и как реализовано?
__Optional in Swift__
> A type that represents either a wrapped value or `nil`, the absence of a value. You use the `Optional` type whenever you use optional values, even if you never type the word `Optional`. Swift's type system usually shows the wrapped type's name with a trailing question mark (`?`) instead of showing the full type name. For example, if a variable has the type `Int?`, that's just another way of writing `Optional<Int>`. The shortened form is preferred for ease of reading and writing code. The types of `shortForm` and `longForm` in the following code sample are the same:
```swift
let shortForm: Int? = Int("42")
let longForm: Optional<Int> = Int("42")
```
The `Optional` type is an enumeration with two cases. `Optional.none` is equivalent to the `nil` literal. `Optional.some(Wrapped)` stores a wrapped value. For example:
```swift
let number: Int? = Optional.some(42)
let noNumber: Int? = Optional.none
print(noNumber == nil)
// Prints "true"
```

```swift
public enum Optional<Wrapped> : ExpressibleByNilLiteral {
/// The absence of a value.
/// In code, the absence of a value is typically written using the `nil`
/// literal rather than the explicit `.none` enumeration case.
case none

/// The presence of a value, stored as `Wrapped`.
case some(Wrapped)
..................
}
```

__Nullability (type) qualifiers in Objective-C__

> The nullability (type) qualifiers express whether a value of a given pointer type can be null (the `_Nullable` qualifier), doesn’t have a defined meaning for null (the `_Nonnull` qualifier), or for which the purpose of null is unclear (the `_Null_unspecified` qualifier). Because nullability qualifiers are expressed within the type system, they are more general than the `nonnull` and `returns_nonnull` attributes, allowing one to express (for example) a `nullable` pointer to an array of `nonnull` pointers. Nullability qualifiers are written to the right of the pointer to which they apply.
> In Objective-C, there is an alternate spelling for the nullability qualifiers that can be used in Objective-C methods and properties using context-sensitive, non-underscored keywords
- `null_unspecified`: bridges to a Swift implicitly-unwrapped optional. This is the default.
- `nonnull`: the value won’t be nil; bridges to a regular reference.
- `nullable`: the value can be nil; bridges to an optional.
- `null_resettable`: the value can never be nil when read, but you can set it to nil to reset it. Applies to properties only.

So for method returns and parameters you can use the double-underscored versions `__nonnull`/`__nullable`/`__null_unspecified` instead of either the single-underscored ones, or instead of the non-underscored ones. The difference is that the single and double underscored ones need to be placed after the type definition, while the non-underscored ones need to be placed before the type definition. Thus, the following declarations are equivalent and are correct:
```objectivec
- (nullable NSNumber *)result
- (NSNumber * __nullable)result
- (NSNumber * _Nullable)result
```
For parameters:
```objectivec
- (void)doSomethingWithString:(nullable NSString *)str
- (void)doSomethingWithString:(NSString * _Nullable)str
- (void)doSomethingWithString:(NSString * __nullable)str
```
For properties:
```objectivec
@property(nullable) NSNumber *status
@property NSNumber *__nullable status
@property NSNumber * _Nullable status
```
Things however complicate when double pointers or blocks returning something different than `void` are involved, as the non-underscore ones are not allowed here:
```objectivec
- (void)compute:(NSError * _Nullable * _Nullable)error
- (void)compute:(NSError * __nullable * _Null_unspecified)error;
// and all other combinations
```
Similar with methods that accept blocks as parameters, please note that the `nonnull`/`nullable` qualifier applies to the block, and not its return type, thus the following are equivalent:
```objectivec
- (void)executeWithCompletion:(nullable void (^)())handler
- (void)executeWithCompletion:(void (^ _Nullable)())handler
- (void)executeWithCompletion:(void (^ __nullable)())handler
```
If the block has a return value, then you're forced into one of the underscore versions:
```objectivec
- (void)convertObject:(nullable id __nonnull (^)(nullable id obj))handler
- (void)convertObject:(id __nonnull (^ _Nullable)())handler
- (void)convertObject:(id _Nonnull (^ __nullable)())handler
// the method accepts a nullable block that returns a nonnull value
// there are some more combinations here, you get the idea
```
10 changes: 1 addition & 9 deletions Main/21_to_do.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,3 @@
* как передвинуть все subviews на 3 pt вверх и влево?
* responder принцип работы
* как отправить сообщение по responder chain?
* как работают категории? в какой момент происходит влияние на классы? что будет если категории пересекутся? зачем у категории есть имя?
* зачем нужен NSCache? В чем от реализации кэша на NSDictionary?
* поддерживает ли NSURLConnection протокол HTTP/2?
* какая типизация у objc? Сильная/слабая, явная/не явная, статическая/динамическая?
* swift optionals, objc new modifiers (`nullable`, etc.). что это и как реализовано?
* dynamic method resolution
* dependency injection
* как сделать миграцию БД
Expand All @@ -17,7 +9,6 @@
* Что такое реактивное программирование? Как работает RAC?
* Что такое функциональное программирование? Какие фичи есть для этого в Swift / Objective-C?
* Difference between Array VS NSArray VS [AnyObject]
* что такое `void *`? а что означает просто `void`? в чем разница между void * и id? что такое id? как определен id? можно ли создать структуру и привести к id? id vs instancetype
* можно ли создать свой root класс? какие есть еще root классы кроме NSObject и NSProxy? можно ли использовать NSObject вместо NSProxy? если ответ «да», то зачем тогда нужен NSProxy?
* как происходит выравнивание указателей на объекты в objc? с чем это связано? какие оптимизации с этим связаны при хранении данных? почему нельзя делать свою реализацию?
* все эти методы допустимы? если нет то какие и почему?
Expand Down Expand Up @@ -94,3 +85,4 @@ struct Value2 {
int32_t foo3;
};
```
* Рефлексия и интроспекция
12 changes: 12 additions & 0 deletions Main/4_objectivec_collections.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
- [Enumeration](#enumeration)
- [Filtering](#filtering)
- [Sorting](#sorting)
- [Зачем нужен NSCache? В чем от реализации кэша на NSDictionary?](#nscache-vs-nsdictionary)

<a name="коллекции-в-objective-c"></a>
# Коллекции в Objective-C
Expand Down Expand Up @@ -375,3 +376,14 @@ selector: 4947.90[ms]
function: 5618.93[ms]
block: 5082.98[ms]
```

<a name="nscache-vs-nsdictionary"></a>
## Зачем нужен NSCache? В чем от реализации кэша на NSDictionary?

`NSCache` objects differ from other mutable collections in a few ways:

* The NSCache class incorporates various auto-removal policies, which ensure that it does not use too much of the system’s memory. The system automatically carries out these policies if memory is needed by other applications. When invoked, these policies remove some items from the cache, minimizing its memory footprint.
* You can add, remove, and query items in the cache from different threads without having to lock the cache yourself.
* Retrieving something from an `NSCache` object returns an autoreleased result.
* Unlike an `NSMutableDictionary` object, a cache does not copy the key objects that are put into it.
* These features are necessary for the `NSCache` class, as the cache may decide to automatically mutate itself asynchronously behind the scenes if it is called to free up memory.
2 changes: 1 addition & 1 deletion Main/6_oop.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ _Как имитировать множественное наследовани
- (void)methodB;
@end
```
__Полиморфизм__ – возможность объектов с одинаковой спецификацией иметь различную реализацию (использование одного имени для решения двух или более схожих, но технически разных задач). Если функция описывает разные реализации (возможно, с различным поведением) для ограниченного набора явно заданных типов и их комбинаций, это называется ситуативным полиморфизмом (ad hoc polimorphism). Ситуативный полиморфизм поддерживается во многих языках посредством перегрузки функций и методов.
__Полиморфизм__ – возможность объектов с одинаковой спецификацией иметь различную реализацию (использование одного имени для решения двух или более схожих, но технически разных задач). Если функция описывает разные реализации (возможно, с различным поведением) для ограниченного набора явно заданных типов и их комбинаций, это называется ситуативным полиморфизмом (ad hoc polymorphism). Ситуативный полиморфизм поддерживается во многих языках посредством перегрузки функций и методов.
Если же код написан отвлеченно от конкретного типа данных и потому может свободно использоваться с любыми новыми типами, имеет место параметрический полиморфизм. Некоторые языки совмещают различные формы полиморфизма, порой сложным образом, что формирует самобытную идеологию в них и влияет на применяемые методологии декомпозиции задач. Например, в Smalltalk любой класс способен принять сообщения любого типа, и либо обработать его самостоятельно (в том числе посредством интроспекции), либо ретранслировать другому классу — таким образом, несмотря на широкое использование перегрузки функций, формально любая операция является неограниченно полиморфной и может применяться к данным любого типа.
<a name="другие-понятия-ооп"></a>
Expand Down
10 changes: 8 additions & 2 deletions Main/7_design_patterns.md
Original file line number Diff line number Diff line change
Expand Up @@ -455,9 +455,17 @@ NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
### Chain of responsibility
Responder (ответчик) – объект, который может реагировать на события и обрабатывать их.
`responderObject : UIResponder; // or NSResponder in MacOS`

<img src="https://github.com/sashakid/ios-guide/blob/master/Images/responder_chain.png">

Цепочка ответственности позволяет вам передавать объекте по цепочке объектов-обработчиков, пока не будет найден необходимый объект обработчик.
```
First responder -> next responder -> …
```
Первый ответчик – ответчик, получивший события первым (например view).

<img src="https://github.com/sashakid/ios-guide/blob/master/Images/responder_chain_in_action.png">

Когда использовать этот паттерн:

* У вас более чем один объект-обработчик.
Expand All @@ -470,8 +478,6 @@ First responder -> next responder -> …
[foo respondsToSelector:@selector(methodName:)];
```
<img src="https://github.com/sashakid/ios-guide/blob/master/Images/responder_chain.png">
<a name="the-target-action-mechanism"></a>
### The Target-Action Mechanism
Expand Down

0 comments on commit a5e1067

Please sign in to comment.