├── LICENSE
├── README.md
└── Resources
├── Artboard-filled-left.png
├── Artboard-filled-right.png
├── Artboard-min.png
├── Articles
├── Autolayout.png
├── Frame-Bounds.png
├── Intrisic Content Size.png
├── Points-Pixels.png
└── Size Classes.png
├── Available QA types.png
├── Devices.jpg
├── English.md
├── Main.png
├── Preview.gif
└── Russian.md
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 Dasha Korneichuk
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | ## Awesome iOS interview questions and answers
4 | 🔛 Get started by picking interview's language and start preparing right now
5 | 
6 |
7 | ## Install the app
8 | Prepare for the iOS-Developer interview on the go. Never miss a tricky question.
9 | You can find free app on the App Store:
10 |
11 | 📲 http://appstore.com/awesomeinterview
12 |
13 |

14 |
15 | ## Questions categories
16 | 
17 |
18 | ## About
19 | Review these iOS interview questions - and get some practical tips along the way.
20 | A handy guide to help those looking to hire an iOS developer for work.
21 |
22 | ## Contribution
23 | 💻 Feel free to add your questions and tasks to database.
24 | 🚀 Just fork the project and pull request.
25 |
--------------------------------------------------------------------------------
/Resources/Artboard-filled-left.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dashvlas/awesome-ios-interview/0092bb4f4ec5aa1fd67b690adb7b1fe47b7e28e9/Resources/Artboard-filled-left.png
--------------------------------------------------------------------------------
/Resources/Artboard-filled-right.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dashvlas/awesome-ios-interview/0092bb4f4ec5aa1fd67b690adb7b1fe47b7e28e9/Resources/Artboard-filled-right.png
--------------------------------------------------------------------------------
/Resources/Artboard-min.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dashvlas/awesome-ios-interview/0092bb4f4ec5aa1fd67b690adb7b1fe47b7e28e9/Resources/Artboard-min.png
--------------------------------------------------------------------------------
/Resources/Articles/Autolayout.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dashvlas/awesome-ios-interview/0092bb4f4ec5aa1fd67b690adb7b1fe47b7e28e9/Resources/Articles/Autolayout.png
--------------------------------------------------------------------------------
/Resources/Articles/Frame-Bounds.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dashvlas/awesome-ios-interview/0092bb4f4ec5aa1fd67b690adb7b1fe47b7e28e9/Resources/Articles/Frame-Bounds.png
--------------------------------------------------------------------------------
/Resources/Articles/Intrisic Content Size.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dashvlas/awesome-ios-interview/0092bb4f4ec5aa1fd67b690adb7b1fe47b7e28e9/Resources/Articles/Intrisic Content Size.png
--------------------------------------------------------------------------------
/Resources/Articles/Points-Pixels.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dashvlas/awesome-ios-interview/0092bb4f4ec5aa1fd67b690adb7b1fe47b7e28e9/Resources/Articles/Points-Pixels.png
--------------------------------------------------------------------------------
/Resources/Articles/Size Classes.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dashvlas/awesome-ios-interview/0092bb4f4ec5aa1fd67b690adb7b1fe47b7e28e9/Resources/Articles/Size Classes.png
--------------------------------------------------------------------------------
/Resources/Available QA types.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dashvlas/awesome-ios-interview/0092bb4f4ec5aa1fd67b690adb7b1fe47b7e28e9/Resources/Available QA types.png
--------------------------------------------------------------------------------
/Resources/Devices.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dashvlas/awesome-ios-interview/0092bb4f4ec5aa1fd67b690adb7b1fe47b7e28e9/Resources/Devices.jpg
--------------------------------------------------------------------------------
/Resources/English.md:
--------------------------------------------------------------------------------
1 | * [UIKit](#uikit)
2 | * [Live Rendering in Storyboards](#how-could-you-setup-live-rendering)
3 | * [Ways of specifing the layout of elements](#ways-of-specifing-the-layout-of-elements)
4 | * [Autolayout formula](#formula-of-autolayout)
5 | * [Size Classes](#size-classes)
6 | * [Intrinsic Content Size](#intrinsic-content-size)
7 | * [Frame and bounds](#whats-the-difference-between-the-frame-and-the-bounds)
8 | * [When bounds origin will be different from 0,0?](#when-bounds-origin-will-be-different-from-00)
9 | * [What do layer objects represent?](#what-are-layer-objects-and-what-do-they-represent)
10 | * [File owner meaning](#file-owner)
11 | * [Life Cycle of App](#app-life-cycle)
12 |
13 | * [Testing](#testing)
14 | * [Test types](#testing)
15 | * [Unit Tests](#unit-tests)
16 | * [Integration Tests](#integration-tests)
17 | * [Functional Tests](#functional-tests)
18 | * [Acceptance Tests](#acceptance-tests)
19 | * [Writing tests for iOS apps](#what-is-the-benefit-writing-tests-in-ios-apps)
20 | * [“Arrange-Act-Assert”](#please-explain-arrange-act-assert)
21 | * [Test Driven Development](#what-is-the-test-driven-development-of-three-simple-rules)
22 | * [Your new app is prone to crashing. What do you do?](#youve-just-been-alerted-that-your-new-app-is-prone-to-crashing-what-do-you-do)
23 |
24 | * [Tasks](#tasks)
25 | * [Explain why a compile time error occurs](#explain-why-a-compile-time-error-occurs-how-can-you-fix-it)
26 | * [Spot the bug that occurs in the code](#spot-the-bug-that-occurs-in-the-code)
27 | * [Consider the following code](#consider-the-following-code)
28 | * [Determine the value of “x” in the Swift code](#determine-the-value-of-x-in-the-swift-code-below)
29 | * [Given two sorted arrays, the task is to merge them in a sorted manner](#given-two-sorted-arrays-the-task-is-to-merge-them-in-a-sorted-manner)
30 | * [Write down the custom method which works similar to reduce() api?](#write-down-the-custom-method-which-works-similar-to-reduce-api)
31 |
32 | * [SDK](#sdk)
33 | * [Application States](#application-states)
34 |
35 | * [Patterns](#patterns)
36 | * [Adapter Pattern](#adapter-pattern)
37 | * [Memento Pattern](#memento-pattern)
38 | * [Factory Method Pattern](#factory-method-pattern)
39 | * [Responder Chain](#responder-chain)
40 | * [Observer Pattern](#observer-pattern)
41 | * [Singleton Pattern](#singleton-pattern)
42 | * [Decorator Pattern](#decorator-pattern)
43 | * [Facade Pattern](#facade-pattern)
44 |
45 | * [Architecture](#architecture)
46 | * [MVC](#mvc)
47 | * [MVVM](#mvvm)
48 | * [MVP](#mvp)
49 | * [Viper](#viper)
50 |
51 | * [OOP](#oop)
52 | * [Inheritance](#inheritance)
53 | * [Polymorphism](#polymorphism)
54 | * [Encapsulation](#encapsulation)
55 |
56 | * [Language](#language)
57 | * [KVO](#kvo)
58 | * [KVC](#kvc)
59 | * [Difference between Delegate and KVO](#what-is-the-difference-between-delegate-and-kvo)
60 | * [What happens when you call autorelease on an object?](#what-happens-when-you-call-autorelease-on-an-object)
61 | * [By calling performSelector:withObject:afterDelay: is the object retained?](#by-calling-performselectorwithobjectafterdelay-is-the-object-retained)
62 | * [Selectors](#selectors)
63 | * [Major differences between Objective-C and Swift](#major-differences-between-objective-c-and-swift)
64 |
65 | * [Swift](#swift)
66 | * [Access Levels](#access-levels)
67 | * [What is an in-out parameter?](#what-is-an-in-out-parameter)
68 | * [Lazy Stored Property vs Stored Property](#lazy-stored-property-vs-stored-property)
69 | * [Open class](#open-class)
70 | * [Final class](#final-class)
71 | * [Struct vs Class](#structs-vs-classes)
72 | * [Swift Standard Library Protocol](#swift-standard-library-protocol)
73 | * [Downcasting](#downcasting)
74 | * [Explain [weak self] and [unowned self]?](#weak-self-and-unowned-self)
75 | * [Lazy in Swift](#lazy-in-swift)
76 | * [What are failable and throwing initializers?](#what-are-failable-and-throwing-initializers)
77 | * [What are type aliases?](#what-are-type-aliases)
78 | * [Raw values and associated values](#in-swift-enumerations-whats-the-difference-between-raw-values-and-associated-values)
79 | * [Non-Escaping and Escaping Closures](#non-escaping-and-escaping-closures)
80 | * [Error handling in Swift](#how-should-one-handle-errors-in-swift)
81 | * [Guard benefits](#what-are-benefits-of-guard)
82 | * [What’s the complexity of the countElements function of a string and why?](#when-applied-to-strings-whats-the-complexity-of-the-countelements-function-and-why)
83 | * [What are designated and convenience initializers?](#what-are-designated-and-convenience-initializers)
84 | * [Swift Transforming Array functions](#swift-transforming-array-functions)
85 | * [Extensions](#extensions)
86 | * [What is defer?](#what-is-defer)
87 | * [What is the difference Any and AnyObject?](#what-is-the-difference-any-and-anyobject)
88 | * [How will you make property’s getter available, but the property is settable only from within code in swift?](#how-will-you-make-propertys-getter-available-but-the-property-is-settable-only-from-within-code-in-swift)
89 | * [Property Wrappers](#property-wrappers)
90 |
91 |
92 | * [Objective-C](#objective-c)
93 | * [What is the difference between _ vs self. in Objective-C?](#what-is-the-difference-between-_-vs-self-in-objective-c)
94 | * [What are blocks in Objective-C?](#what-are-blocks-in-objective-c)
95 | * [“Strong” and “Weak” references](#strong-and-weak-references)
96 | * [Strong, Weak, Readonly and Copy](#what-is-the-difference-strong-weak-readonly-and-copy)
97 | * [@dynamic in Objective-C](#what-is-dynamic-in-objective-c)
98 | * [NSError object](#what-is-made-up-of-nserror-object)
99 |
100 | * [General](#general)
101 | * [What is the difference in functional programming and OOPS?](#what-is-the-difference-in-functional-programming-and-oops)
102 | * [HTTP request types](#http-request-types)
103 | * [Communication protocols](#communication-protocols)
104 | * [Network socket](#network-socket)
105 | * [WebSocket](#websocket)
106 | * [TCP Stream Socket](#tcp-stream-socket)
107 | * [UDP Datagram Socket](#udp-datagram-socket)
108 | * [CFStream](#cfstream)
109 | * [NSStream](#nsstream)
110 | * [REST](#rest)
111 | * [SOAP](#soap)
112 | * [Deep and shallow copy](#deep-and-shallow-copy)
113 | * [Difference between functions and methods in Swift?](#what-is-the-difference-between-functions-and-methods-in-swift)
114 | * [Protocol Oriented Programming](#protocol-oriented-programming)
115 |
116 | * [Data](#data)
117 | * [How does NSManagedObjectContext work?](#how-does-nsmanagedobjectcontext-work)
118 | * [NSFetchedResultsController](#nsfetchedresultscontroller)
119 | * [NSPersistentContainer](#nspersistentcontainer)
120 | * [Managed object context and the functionality that it provides](#managed-object-context-and-the-functionality-that-it-provides)
121 | * [What is NSFetchRequest?](#what-is-nsfetchrequest)
122 |
123 | * [Concurrency](#concurrency)
124 | * [Concurrency in Mac OS and iOS](#different-ways-of-achieving-concurrency-in-mac-os-and-ios)
125 | * [POSIX Threads](#posix-threads)
126 | * [NSThread](#nsthread)
127 | * [GCD](#gcd)
128 | * [Quality of Service (QoS)](#quality-of-service-qos)
129 | * [NSOperationQueue](#nsoperationqueue)
130 | * [Cancel NSOperation problem](#cancel-nsoperation-problem)
131 | * [DispatchGroup](#what-is-dispatchgroup)
132 | * [@synchronized](#synchronized)
133 | * [Synchronous & asynchronous tasks](#what-is-the-difference-between-synchronous--asynchronous-task)
134 | * [Semaphore](#semaphore)
135 | * [Lock](#lock)
136 | * [Mutex](#mutex)
137 | * [Semaphore vs Mutex vs Lock](#semaphore-vs-mutex-vs-lock)
138 |
139 | # UIKit
140 |
141 | ## How could you setup Live Rendering?
142 | With `@IBInspectable` and `@IBDesignable`, it’s possible to build a custom interface for configuring your custom controls and have them rendered in real-time while designing your project.
143 |
144 | `@IBInspectable` properties provide new access to an old feature: user-defined runtime attributes. Currently accessible from the identity inspector, these attributes have been available since before Interface Builder was integrated into Xcode. They provide a powerful mechanism for configuring any key-value coded property of an instance in a NIB, XIB, or storyboard.
145 |
146 | Built-in Cocoa types can also be extended to have inspectable properties beyond the ones already in Interface Builder’s attribute inspector. If you like rounded corners, you’ll love this UIView extension:
147 |
148 | ```swift
149 | extension UIView {
150 | @IBInspectable var cornerRadius: CGFloat {
151 | get {
152 | return layer.cornerRadius
153 | }
154 | set {
155 | layer.cornerRadius = newValue
156 | layer.masksToBounds = newValue > 0
157 | }
158 | }
159 | }
160 | ```
161 |
162 | The attribute `@IBDesignable` lets Interface Builder perform live updates on a particular view.
163 | This allows seeing how your custom views will appear without building and running your app after each change.
164 |
165 | To mark a custom view as `IBDesignable`, prefix the class name with `@IBDesignable` (or the IB_DESIGNABLE macro in Objective-C). Your initializers, layout, and drawing methods will be used to render your custom view right on the canvas:
166 | ```swift
167 | @IBDesignable
168 | class MyCustomView: UIView {
169 | ...
170 | }
171 | ```
172 |
173 | ## Ways of specifing the layout of elements
174 |
175 | Here are a few common ways to specify the layout of elements in a UIView:
176 |
177 | - Using `Interface Builder`, you can add a `XIB file` to your project, layout elements within it, and then load the XIB in your application code (either automatically, based on naming conventions, or manually). Also, using InterfaceBuilder you can create a storyboard for your application.
178 | - You can your own code to use NSLayoutConstraints to have elements in a view arranged by Auto Layout.
179 | - You can create CGRects describing the exact coordinates for each element and pass them to UIView’s
180 | ```objectivec
181 | - (id)initWithFrame:(CGRect)frame method.
182 | ```
183 | ## Formula of Autolayout
184 |
185 |
186 | ## Size Classes
187 | A size class is a new technology used by iOS to allow you to custom your app for a given device class, based on its orientation and screen size.
188 |
189 | There are presently four size classes:
190 | - Horizontal Regular
191 | - Horizontal Compact
192 | - Vertical Regular
193 | - Vertical Compact
194 |
195 |
196 |
197 | ## Intrinsic Content Size
198 | The Intrinsic Content Size is one of the most powerful features you gain when you opt-in to using Auto Layout to describe your interfaces. When a view has an intrinsic content size, it is promising Auto Layout that it will have a predefined size that the engine can use to calculate and lay out its views
199 |
200 |
201 |
202 | ## What’s the difference between the frame and the bounds?
203 | `The bounds` of an UIView is the rectangle, expressed as a location (x,y) and size (width,height) relative to its own coordinate system (0,0)
204 | `The frame` of an UIView is the rectangle, expressed as a location (x,y) and size (width,height) relative to the superview it is contained within.
205 |
206 |
207 |
208 | ## When bounds origin will be different from 0,0?
209 |
210 | Let's take an example of `UIScrollView`:
211 | UIScrollView's bounds.origin will not be (0, 0) when its contentOffset is not (0, 0).
212 |
213 | ## What are layer objects and what do they represent?
214 | `Layer objects` are data objects which represent visual content. Layer objects are used by views to render their content. Custom layer objects can also be added to the interface to implement complex animations and other types of sophisticated visual effects.
215 |
216 | ## File owner
217 |
218 | Two points to be remembered:
219 |
220 | - The File owner is the object that loads the nib, i.e. that object which receives the message `loadNibNamed:` or `initWithNibName:`.
221 | - If you want to access any objects in the nib after loading it, you can set an outlet in the file owner.
222 |
223 | So you created a fancy view with lots of buttons, subviews etc . If you want to modify any of these views / objects any time after loading the nib FROM the loading object (usually a view or window controller) you set outlets for these objects to the file owner. It's that simple.
224 |
225 | This is the reason why by default all View Controllers or Window Controllers act as file owners, and also have an outlet to the main window or view object in the nib file: because duh, if you're controlling something you'll definitely need to have an outlet to it so that you can send messages to it.
226 |
227 | The reason it's called file owner and given a special place, is because unlike the other objects in the nib, the file owner is external to the nib and is not part of it. In fact, it only becomes available when the nib is loaded. So the file owner is a stand-in or proxy for the actual object which will later load the nib.
228 |
229 | ## App Life Cycle
230 |
231 | application:willFinishLaunchingWithOptions:—This method is your app’s first chance to execute code at launch time.
232 |
233 | application:didFinishLaunchingWithOptions:—This method allows you to perform any final initialization before your app is displayed to the user.
234 |
235 | applicationDidBecomeActive:—Lets your app know that it is about to become the foreground app. Use this method for any last minute preparation.
236 |
237 | applicationWillResignActive:—Lets you know that your app is transitioning away from being the foreground app. Use this method to put your app into a quiescent state.
238 |
239 | applicationDidEnterBackground:—Lets you know that your app is now running in the background and may be suspended at any time.
240 |
241 | applicationWillEnterForeground:—Lets you know that your app is moving out of the background and back into the foreground, but that it is not yet active.
242 |
243 | applicationWillTerminate:—Lets you know that your app is being terminated. This method is not called if your app is suspended.
244 |
245 |
246 | # Testing
247 |
248 | ### Unit Tests
249 | Tests the smallest unit of functionality, typically a method/function (e.g. given a class with a particular state, calling x method on the class should cause y to happen). Unit tests should be focussed on one particular feature (e.g., calling the pop method when the stack is empty should throw an InvalidOperationException). Everything it touches should be done in memory; this means that the test code and the code under test shouldn't:
250 |
251 | 1. Call out into (non-trivial) collaborators
252 | 2. Access the network
253 | 3. Hit a database
254 | 4. Use the file system
255 | 5. Spin up a thread
256 |
257 | Any kind of dependency that is slow / hard to understand / initialise / manipulate should be stubbed / mocked / whatevered using the appropriate techniques so you can focus on what the unit of code is doing, not what its dependencies do.
258 | In short, unit tests are as simple as possible, easy to debug, reliable (due to reduced external factors), fast to execute and help to prove that the smallest building blocks of your program function as intended before they're put together. The caveat is that, although you can prove they work perfectly in isolation, the units of code may blow up when combined which brings us to ...
259 |
260 | ### Integration Tests
261 | Integration tests build on unit tests by combining the units of code and testing that the resulting combination functions correctly. This can be either the innards of one system, or combining multiple systems together to do something useful. Also, another thing that differentiates integration tests from unit tests is the environment. Integration tests can and will use threads, access the database or do whatever is required to ensure that all of the code and the different environment changes will work correctly.
262 | If you've built some serialization code and unit tested its innards without touching the disk, how do you know that it'll work when you are loading and saving to disk? Maybe you forgot to flush and dispose filestreams. Maybe your file permissions are incorrect and you've tested the innards using in memory streams. The only way to find out for sure is to test it 'for real' using an environment that is closest to production.
263 | The main advantage is that they will find bugs that unit tests can't such as wiring bugs (e.g. an instance of class A unexpectedly receives a null instance of B) and environment bugs (it runs fine on my single-CPU machine, but my colleague's 4 core machine can't pass the tests). The main disadvantage is that integration tests touch more code, are less reliable, failures are harder to diagnose and the tests are harder to maintain.
264 | Also, integration tests don't necessarily prove that a complete feature works. The user may not care about the internal details of my programs, but I do!
265 |
266 | ### Functional Tests
267 | Functional tests check a particular feature for correctness by comparing the results for a given input against the specification. Functional tests don't concern themselves with intermediate results or side-effects, just the result (they don't care that after doing x, object y has state z). They are written to test part of the specification such as, "calling function `Square(x)` with the argument of `2` returns `4`".
268 |
269 | ### Acceptance Tests
270 | Acceptance testing seems to be split into two types:
271 | Standard acceptance testing involves performing tests on the full system (e.g. using your web page via a web browser) to see whether the application's functionality satisfies the specification. E.g. "clicking a zoom icon should enlarge the document view by 25%." There is no real continuum of results, just a pass or fail outcome.
272 | The advantage is that the tests are described in plain English and ensures the software, as a whole, is feature complete. The disadvantage is that you've moved another level up the testing pyramid. Acceptance tests touch mountains of code, so tracking down a failure can be tricky.
273 | Also, in agile software development, user acceptance testing involves creating tests to mirror the user stories created by/for the software's customer during development. If the tests pass, it means the software should meet the customer's requirements and the stories can be considered complete. An acceptance test suite is basically an executable specification written in a domain specific language that describes the tests in the language used by the users of the system.
274 |
275 | ## What is the benefit writing tests in iOS apps?
276 | Tests gives us a clear perspective on the API design, by getting into the mindset of being a client of the API before it exists.
277 | Good tests serve as great documentation of expected behavior.
278 | It gives us confidence to constantly refactor our code because we know that if we break anything our tests fail.
279 | If tests are hard to write its usually a sign architecture could be improved. Following RGR ( Red — Green — Refactor ) helps you make improvements early on.
280 |
281 | ## Please explain “Arrange-Act-Assert”
282 | AAA is a pattern for arranging and formatting code in Unit Tests. If we were to write XCTests each of our tests would group these functional sections, separated by blank lines:
283 | Arrange all necessary preconditions and inputs.
284 | Act on the object or method under test.
285 | Assert that the expected results have occurred.
286 |
287 | ## What is the Test Driven Development of three simple rules?
288 | You are not allowed to write any production code unless it is to make a failing unit test pass.
289 | You are not allowed to write any more of a unit test than is sufficient to fail; and compilation failures are failures.
290 | You are not allowed to write any more production code than is sufficient to pass the one failing unit test.
291 |
292 | ## You’ve just been alerted that your new app is prone to crashing. What do you do?
293 |
294 | This classic interview question is designed to see how well your prospective programmer can solve problems. What you’re looking for is a general methodology for isolating a bug, and their ability to troubleshoot issues like sudden crashes or freezing. In general, when something goes wrong within an app, a standard approach might look something like this:
295 |
296 | #### Determine the iOS version and make or model of the device.
297 | #### Gather enough information to reproduce the issue.
298 | #### Acquire device logs, if possible.
299 |
300 | Once you have an idea as to the nature of the issue, acquire tooling or create a unit test and begin debugging.
301 | A great answer would include all of the above, with specific examples of debugging tools like Buglife or ViewMonitor, and a firm grasp of software debugging theory—knowledge on what to do with compile time errors, run-time errors, and logical errors. The one answer you don’t want to hear is the haphazard approach—visually scanning through hundreds of lines of code until the error is found. When it comes to debugging software, a methodical approach is must.
302 |
303 | # Tasks
304 |
305 | ## Explain why a compile time error occurs. How can you fix it?
306 | Task:
307 | The following code snippet results in a compile time error:
308 | ```objectivec
309 | struct IntStack {
310 | var items = [Int]()
311 | func add(x: Int) {
312 | items.append(x) // Compile time error here
313 | }
314 | }
315 | ```
316 |
317 | Solution:
318 | Structures are value types. By default, the properties of a value type cannot be modified from within its instance methods.
319 | However, you can optionally allow such modification to occur by declaring the instance methods as ‘mutating’:
320 | ```objectivec
321 | struct IntStack {
322 | var items = [Int]()
323 | mutating func add(x: Int) {
324 | items.append(x) // All good!
325 | }
326 | }
327 | ```
328 |
329 | ## Spot the bug that occurs in the code
330 |
331 | ```objectivec
332 | @interface MyCustomController : UIViewController
333 |
334 | @property (strong, nonatomic) UILabel *alert;
335 |
336 | @end
337 |
338 | @implementation MyCustomController
339 |
340 | - (void)viewDidLoad {
341 | CGRect frame = CGRectMake(100, 100, 100, 50);
342 | self.alert = [[UILabel alloc] initWithFrame:frame];
343 | self.alert.text = @"Please wait...";
344 | [self.view addSubview:self.alert];
345 | dispatch_async(
346 | dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),
347 | ^{
348 | sleep(10);
349 | self.alert.text = @"Waiting over";
350 | }
351 | );
352 | }
353 | ```
354 |
355 | Solution:
356 | All UI updates must be performed on the main thread. Global dispatch queues do not make any guarantees so code should be modified to run the UI update on the main thread. Here is the fix below:
357 |
358 | ```objectivec
359 | dispatch_async(
360 | dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),
361 | ^{
362 | sleep(10);
363 | dispatch_async(dispatch_get_main_queue(), ^{
364 | self.alert.text = @"Waiting over";
365 | });
366 | });
367 | ```
368 |
369 | ## Consider the following code:
370 | Task:
371 | ```objectivec
372 | var defaults = UserDefaults.standard()
373 | var userPref = defaults.stringForKey("userPref")!
374 | printString(userPref)
375 |
376 | func printString(string: String) {
377 | print(string)
378 | }
379 | ```
380 |
381 | Solution:
382 | The second line uses the stringForKey method of UserDefaults, which returns an optional, to account for the key not being found, or for the corresponding value not being convertible to a string.
383 |
384 | During its execution, if the key is found and the corresponding value is a string, the above code works correctly. But if the key doesn’t exist, or the corresponding value is not a string, the app crashes with the following error:
385 |
386 | fatal error: unexpectedly found nil while unwrapping an Optional value
387 | The reason is that the forced unwrapping operator ! is attempting to force unwrap a value from a nil optional. The forced unwrapping operator should be used only when an optional is known to contain a non-nil value.
388 |
389 | The solution consists of making sure that the optional is not nil before force-unwrapping it:
390 | ```objectivec
391 | let userPref = defaults.stringForKey("userPref")
392 | if userPref != nil {
393 | printString(userPref!)
394 | }
395 | ```
396 |
397 | ## Determine the value of “x” in the Swift code below
398 | Task:
399 | ```swift
400 | var a1 = [1, 2, 3, 4, 5]
401 | var a2 = a1
402 | a2.append(6)
403 | var x = a1.count
404 | ```
405 |
406 | Solution:
407 | In Swift, arrays are implemented as structs, making them value types rather than reference types (i.e., classes). When a value type is assigned to a variable as an argument to a function or method, a copy is created and assigned or passed. As a result, the value of “x” or the count of array “a1” remains equal to 5 while the count of array “a2” is equal to 6, appending the integer “6” onto a copy of the array “a1.” The arrays appear in the box below.
408 | ```swift
409 | a1 = [1, 2, 3, 4, 5]
410 | a2 = [1, 2, 3, 4, 5, 6]
411 | ```
412 |
413 | ## Given two sorted arrays, the task is to merge them in a sorted manner
414 |
415 | Input : arr1 = [1, 3, 4, 5]
416 | arr2 = [2, 4, 6, 8]
417 | Output : arr3 = [1, 2, 3, 4, 5, 6, 7, 8]
418 |
419 | 1. Method 1 (O(n1 * n2) Time and O(1) Extra Space)
420 |
421 | Create an array arr3 of size n1 + n2.
422 | Copy all n1 elements of arr1 to arr3
423 | Traverse arr2 and one by one insert elements (like insertion sort) of arr3 to arr1. This step take O(n1 * n2) time.
424 |
425 | 2. Method 2 (O(n1 + n2) Time and O(n1 + n2) Extra Space)
426 | The idea is to use Merge function of Merge sort.
427 |
428 | Create an array arr3 of size n1 + n2.
429 | Simultaneously traverse arr1 and arr2.
430 | Pick smaller of current elements in arr1 and arr2, copy this smaller element to next position in arr3 and move ahead in arr3 and the array whose element is picked.
431 | If there are are remaining elements in arr1 or arr2, copy them also in arr3.
432 |
433 | ## Write down the custom method which works similar to reduce() api
434 | ```swift
435 | sum = array.reduce(0, +)
436 | //reduce() here is an ((Int, ((Int, Int) -> Bool)) -> Int)
437 | //and the + operator is func +(lhs: Int, rhs: Int) -> Bool,
438 | //... or ((Int, Int) -> Bool), so there's no need to define reduce's closure.
439 | ```
440 |
441 | # SDK
442 |
443 | ## Application States
444 | The iOS application states are as follows:
445 |
446 | Not running state: The app has not been launched or was running but was terminated by the system.
447 |
448 | #### Inactive state:
449 | The app is running in the foreground but is currently not receiving events. (It may be executing other code though.) An app usually stays in this state only briefly as it transitions to a different state. The only time it stays inactive for any period of time is when the user locks the screen or the system prompts the user to respond to some event (such as an incoming phone call or SMS message).
450 |
451 | #### Active state:
452 | The app is running in the foreground and is receiving events. This is the normal mode for foreground apps.
453 |
454 | #### Background state:
455 | The app is in the background and executing code. Most apps enter this state briefly on their way to being suspended. However, an app that requests extra execution time may remain in this state for a period of time. In addition, an app being launched directly into the background enters this state instead of the inactive state.
456 |
457 | #### Suspended state:
458 | While suspended, an app remains in memory but does not execute any code. When a low-memory condition occurs, the system may purge suspended apps without notice to make more space for the foreground app.
459 |
460 | # Patterns
461 |
462 | ## Delegation pattern
463 |
464 | The delegation pattern is a powerful pattern used in building iOS applications. The basic idea is that one object will act on another object's behalf or in coordination with another object. The delegating object typically keeps a reference to the other object (delegate) and sends a message to it at the appropriate time. It is important to note that they have a one to one relationship.
465 |
466 | ## Adapter Pattern
467 | An Adapter allows classes with incompatible interfaces to work together. It wraps itself around an object and exposes a standard interface to interact with that object.
468 |
469 | ## Memento Pattern
470 | In Memento Pattern saves your stuff somewhere. Later on, this externalized state can be restored without violating encapsulation; that is, private data remains private. One of Apple’s specialized implementations of the Memento pattern is Archiving.
471 |
472 | ## Factory Method Pattern
473 | Factory Method is used to replace class constructors, to abstract and hide objects initialization so that the type can be determined at runtime, and to hide and contain switch/if statements that determine the type of object to be instantiated.
474 |
475 | ## Responder Chain
476 | A ResponderChain is a hierarchy of objects that have the opportunity to respond to events received.
477 |
478 | ## Observer Pattern
479 | In the Observer pattern, one object notifies other objects of any state changes.
480 |
481 | ## Singleton Pattern
482 | The Singleton design pattern ensures that only one instance exists for a given class and that there’s a global access point to that instance. It usually uses lazy loading to create the single instance when it’s needed the first time.
483 |
484 | ## Decorator Pattern
485 | The Decorator pattern dynamically adds behaviors and responsibilities to an object without modifying its code. It’s an alternative to subclassing where you modify a class’s behavior by wrapping it with another object.
486 |
487 | ## Facade Pattern
488 | The Facade design pattern provides a single interface to a complex subsystem. Instead of exposing the user to a set of classes and their APIs, you only expose one simple unified API.
489 |
490 | # Architecture
491 |
492 | ## MVC
493 | MVC stands for **Model-View-Controller**. It is a software architecture pattern for implementing user interfaces.
494 |
495 | MVC consists of three layers: the model, the view, and the controller.
496 | - The **model layer** is typically where the data resides (persistence, model objects, etc)
497 | - The **view layer** is typically where all the UI interface lies. Things like displaying buttons and numbers belong in the view layer. The view layer does not know anything about the model layer and vice versa.
498 | - The **controller (view controller)** is the layer that integrates the view layer and the model layer together.
499 |
500 | ## MVVM
501 |
502 | The MVVM defines the following
503 | · The View , which is generally passive, corresponds to the Presentation Layer
504 | · The Model , corresponds to the Business Logic Layer and is identical to the MVC pattern
505 | · The View Model sits between the View and the Model , corresponds to the Application Logic Layer
506 |
507 | The key aspect of the MVVM pattern is the binding between the View and the View Model. In other words, the View is automatically notified of changes to the View Model.
508 |
509 | In iOS, this can be accomplished using Key-Value-Observer (KVO) Pattern. In the KVO Pattern (https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/KeyValueObserving/KeyValueObserving.html) , one object is automatically notified of changes to the state of another object. In Objective C, this facility is built into the run-time. However, it’s not as straightforward in Swift. One option would be to add the “dynamic” modifiers to properties that need to be dynamically dispatched. However, this is limiting as objects now need to be of type NSObject. The alternate is to simulate this behavior by defining a generic type that acts as a wrapper around properties that are observable.
510 |
511 | ## MVP
512 | The MVP defines the following
513 | · The View , which is generally passive, corresponds to the Presentation Layer
514 | · The Model , corresponds to the Business Logic Layer and is identical to the MVC pattern
515 | · The Presenter sits between the View and the Model , corresponds to the Application Logic Layer.
516 | A View is typically associated with one Presenter.
517 |
518 | In iOS, the interaction between the View and Presenter can be implemented using the Delegation Pattern (https://developer.apple.com/library/content/documentation/General/Conceptual/DevPedia-CocoaCore/Delegation.html). The Delegation Pattern allows one object to delegate tasks to another object. In iOS, the pattern is implemented using a Protocol. The Protocol defines the interface that is to be implemented by the delegate.
519 |
520 | In the MVP pattern, the View and Presenter are aware of each other. The Presenter holds a reference to the view it is associated with.
521 |
522 | The PresenterProtocol defines the base set of methods that any Presenter must implement. Applications must extend this Protocol to include application specific methods.
523 |
524 | ```swift
525 | protocol PresenterProtocol: class{
526 | func attachPresentingView(_view:PresentingViewProtocol)
527 | func detachPresentingView(_view:PresentingViewProtocol)
528 | }
529 | ```
530 |
531 | The PresentingViewProtocol defines the base set of methods that View must implement. By providing default implementation of the methods in this interface, the conformant view does not have to provide its own implementation. This interface can be extended to define application specific methods.
532 |
533 | ```swift
534 | protocol PresentingViewProtocol: class{
535 | func dataStartedLoading()
536 | func dataFinishedLoading()
537 | func showErrorAlertWithTitle(_title:String?, message:String)
538 | func showSuccessAlertWithTitle(_title:String?, message:String)
539 | }
540 | ```
541 |
542 | ## Viper
543 |
544 | This architecture is based on Single Responsibility Principle which leads to a clean architecture.
545 |
546 | - View: The responsibility of the view is to send the user actions to the presenter and shows whatever the presenter tells it.
547 | - Interactor: This is the backbone of an application as it contains the business logic.
548 | - Presenter: Its responsibility is to get the data from the interactor on user actions and after getting data from the interactor, it sends it to the view to show it. It also asks the router/wireframe for navigation.
549 | - Entity: It contains basic model objects used by the Interactor.
550 | - Router: It has all navigation logic for describing which screens are to be shown when. It is normally written as a wireframe.
551 |
552 | # OOP
553 |
554 | ## Inheritance
555 | It allows a class to be defined that has a certain set of characteristics (such as methods and instance variables) and then other classes to be created which are derived from that class. The derived class inherits all of the features of the parent class and typically then adds some features of its own.
556 |
557 | ## Polymorphism
558 | The word polymorphism means having many forms. Typically, polymorphism occurs when there is a hierarchy of classes and they are related by inheritance.
559 |
560 | Objective-C polymorphism means that a call to a member function will cause a different function to be executed depending on the type of object that invokes the function.
561 |
562 | Consider the example, we have a class Shape that provides the basic interface for all the shapes. Square and Rectangle are derived from the base class Shape.
563 |
564 | ## Encapsulation
565 | Encapsulation is an Object-Oriented Programming concept that binds together the data and functions that manipulate the data and that keeps both safe from outside interference and misuse. Data encapsulation led to the important OOP concept of data hiding.
566 |
567 | Data encapsulation is a mechanism of bundling the data and the functions that use them, and data abstraction is a mechanism of exposing only the interfaces and hiding the implementation details from the user.
568 |
569 | # Language
570 |
571 | ## KVO
572 | KVO stands for `Key-Value Observing` and allows a controller or class to observe changes to a property value. In KVO, an object can ask to be notified of any changes to a specific property; either its own or that of another object.
573 |
574 | ## KVC
575 | KVC adds stands for `Key-Value Coding`. It’s a mechanism by which an object’s properties can be accessed using string’s at runtime rather than having to statically know the property names at development time.
576 |
577 | ## Selectors
578 | In Objective-C, selector has two meanings. It can be used to refer simply to the name of a method when it’s used in a source-code message to an object. It also, though, refers to the unique identifier that replaces the name when the source code is compiled. Compiled selectors are of type SEL. All methods with the same name have the same selector. You can use a selector to invoke a method on an object—this provides the basis for the implementation of the target-action design pattern in Cocoa
579 |
580 | ```objectivec
581 | [friend performSelector:@selector(gossipAbout:) withObject:aNeighbor]
582 | is equivalent to
583 | [friend gossipAbout:aNeighbor]
584 | ```
585 |
586 | ## What is the difference between Delegate and KVO?
587 | Both are ways to have relationships between objects. Delegation is a one-to-one relationship where one object implements a delegate protocol and another uses it and sends messages to it, assuming that those methods are implemented since the receiver promised to comply to the protocol. KVO is a many-to-many relationship where one object could broadcast a message and one or multiple other objects can listen to it and react. KVO does not rely on protocols. KVO is the first step and the fundamental block of reactive programming (RxSwift, ReactiveCocoa, etc.)
588 |
589 | ## By calling performSelector:withObject:afterDelay: is the object retained?
590 | Yes, the object is retained. It creates a timer that calls a selector on the current threads run loop. It may not be 100% precise time-wise as it attempts to dequeue the message from
591 | the run loop and perform the selector
592 |
593 | ## What happens when you call autorelease on an object?
594 | When you send an object a autorelease message, its retain count is decremented by 1 at some stage in the future. The object is added to an autorelease pool on the current thread. The main thread loop creates an autorelease pool at the beginning of the function, and release it at the end. This establishes a pool for the lifetime of the task. However, this also means that any autoreleased objects created during the lifetime of the task are not disposed of until the task completes. This may lead to the taskʼs memory footprint increasing unnecessarily. You can also consider creating pools with a narrower scope or use NSOperationQueue with itʼs own autorelease pool. (Also important – You only release or autorelease objects you own.)
595 |
596 | ## Major differences between Objective-C and Swift
597 | What Most People Say: “I prefer the look and feel of Swift and I certainly won’t miss Objective-C’s square brackets.”
598 | What You Should Say: “While Objective-C is more flexible than Swift, Swift is designed to catch programming errors much earlier. For instance, many errors that would occur at runtime in Objective-C—like sending a message to an object that doesn’t implement it—are now checked at compile-time. Objective-C can accomplish all of the things Swift can, but Swift can do so more safely. Swift supports more programming language features, like optionals, tuples and generics.”
599 | Why You Should Say It: The second answer demonstrates greater familiarity with the operational differences between Objective-C and Swift. It’s fairly easy to learn another programming language once you understand its strengths, weaknesses and compatibility with other languages.
600 |
601 | ## Swift
602 |
603 | ## Access Levels
604 |
605 | 1. Public
606 |
607 | Enables entities to be processed with in any source file from their defining module, a source file from another module that imports the defining module.
608 |
609 | 2. Internal
610 |
611 | Enables entities to be used within any source file from their defining module, but not in any source file outside of that module.
612 |
613 | 3. Private
614 |
615 | Restricts the use of an entity to its own defining source file. Private access plays role to hide the implementation details of a specific code functionality.
616 |
617 | ## What is an in-out parameter?
618 |
619 | In-out parameter lets you change the value of a function parameter from within the body of that function.
620 |
621 | ## Lazy Stored Property vs Stored Property
622 |
623 | 1. The closure associated to the lazy property is executed only if you read that property. So if for some reason that property is not used (maybe because of some decision of the user) you avoid unnecessary allocation and computation.
624 | You can populate a lazy property with the value of a stored property.
625 |
626 | 2. You can use self inside the closure of a lazy property. If you need to use self inside the function. In fact, if you're using a class rather than a structure, you should also declare [unowned self] inside your function so that you don't create a strong reference cycle(check the code below).
627 |
628 | ```swift
629 |
630 | import UIKit
631 | import Foundation
632 |
633 | class InterviewTest {
634 | var name: String
635 | lazy var greeting : String = { [unowned self] in
636 | return “Hello \(self.name)”
637 | }()
638 |
639 | init(name: String) {
640 | self.name = name
641 | }
642 | }
643 |
644 | let testObj = InterviewTest(name:”abhi”)
645 | testObj.greeting
646 |
647 | ```
648 | Note: Remember, the point of lazy properties is that they are computed only when they are first needed, after which their value is saved. So, if you call the iOSResumeDescription for the second time, the previously saved value is returned.
649 |
650 | ## Open class
651 | By adding the keyword open in front of the method name, we allow the method to being overridden
652 |
653 | ## Final class
654 | By adding the keyword final in front of the method name, we prevent the method from being overridden
655 |
656 | ## Structs vs Classes
657 | 1. Inheritance.
658 |
659 | Structures can't inherit in swift.
660 |
661 | ```swift
662 | class Vehicle {
663 | }
664 |
665 | class Car : Vehicle {
666 | }
667 | ```
668 |
669 | 2. Pass By
670 |
671 | Swift structures pass by value and class instances pass by reference.
672 |
673 | 3. Thread Safety
674 |
675 | Structs are thread-safe
676 |
677 | ## Swift Standard Library Protocol
678 | There are a few different protocol. Equatable protocol, that governs how we can distinguish between two instances of the same type. That means we can analyze. If we have a specific value is in our array. The comparable protocol, to compare two instances of the same type and sequence protocol: prefix(while:) and drop(while:) [SE-0045].
679 | Swift 4 introduces a new Codable protocol that lets us serialize and deserialize custom data types without writing any special code.
680 |
681 | ## What are failable and throwing initializers?
682 |
683 | Very often initialization depends on external data, this data can exist as it can not, for that Swift provides two ways to deal with this.
684 | Failable initializers return nil of there is no data, and let the developer “create” a different path in the application based on that.
685 | In other hand throwing initializers returns an error on initialization instead of returning nil.
686 |
687 | ## Downcasting
688 | When we’re casting an object to another type in Objective-C, it’s pretty simple since there’s only one way to do it. In Swift, though, there are two ways to cast — one that’s safe and one that’s not .
689 | as used for upcasting and type casting to bridged type
690 | as? used for safe casting, return nil if failed
691 | as! used to force casting, crash if failed. should only be used when we know the downcast will succeed.
692 |
693 | ## [weak self] and [unowned self]
694 | unowned does the same as weak with one exception: The variable will not become nil and therefore the variable must not be an optional.
695 | But when you try to access the variable after its instance has been deallocated. That means, you should only use unowned when you are sure, that this variable will never be accessed after the corresponding instance has been deallocated.
696 | However, if you don’t want the variable to be weak AND you are sure that it can’t be accessed after the corresponding instance has been deallocated, you can use unowned.
697 | By declaring it [weak self] you get to handle the case that it might be nil inside the closure at some point and therefore the variable must be an optional. A case for using [weak self] in an asynchronous network request, is in a view controller where that request is used to populate the view.
698 |
699 | ## Lazy in Swift
700 | An initial value of the lazy stored properties is calculated only when the property is called for the first time. There are situations when the lazy properties come very handy to developers.
701 |
702 | ## Raw and associated values
703 | This question tests the developer’s understanding of enumeration in Swift. Enumeration provides a type-safe method of working with a group of related values. Raw values are compile time-set values directly assigned to every case within an enumeration, as in the example detailed below:
704 | ```swift
705 | enum Alphabet: Int {
706 | case A = 1
707 | case B
708 | case C
709 | }
710 | ```
711 |
712 | In the above example code, case “A” was explicitly assigned a raw value integer of 1, while cases “B” and “C” were implicitly assigned raw value integers of 2 and 3, respectively. Associated values allow you to store values of other types alongside case values, as demonstrated below:
713 | ```swift
714 | enum Alphabet: Int {
715 | case A(Int)
716 | case B
717 | case C(String)
718 | }
719 | ```
720 |
721 | ## What are type aliases?
722 |
723 | Swift comes with two type aliases to represent non-specific types “Any” and “AnyObject”.
724 | AnyObject represents an instance of any class type and Any is the most generic representation of a type in Swift, it can represent an instance of absolutely any type including functions.
725 |
726 | ## Non-Escaping and Escaping Closures
727 | The lifecycle of a non-escaping closure is simple:
728 | Pass a closure into a function
729 | The function runs the closure (or not)
730 | The function returns
731 | Escaping closure means, inside the function, you can still run the closure (or not); the extra bit of the closure is stored some place that will outlive the function. There are several ways to have a closure escape its containing function:
732 | Asynchronous execution: If you execute the closure asynchronously on a dispatch queue, the queue will hold onto the closure for you. You have no idea when the closure will be executed and there’s no guarantee it will complete before the function returns.
733 | Storage: Storing the closure to a global variable, property, or any other bit of storage that lives on past the function call means the closure has also escaped.
734 |
735 | ## What are designated and convenience initializers?
736 |
737 | Designated initializers are:
738 | - The CENTRAL point of initialization of a class.
739 | - Classes MUST have at least one.
740 | - Is the responsible for initializing stored properties.
741 | - Is the responsible for calling super init.
742 |
743 | Convenience initializers are:
744 | - SECONDARY supporting initializers for a class.
745 | - It can only call a designated initializer that is defined in the same class
746 | - It can also call another convenience initializers defined in the same class
747 | - They are not required, that sort of implied. they are just initializers that we can write for a CONVENIENCE use case
748 | - In a class, They use the keyword “convenience” before the init keyword.
749 |
750 | Finally here are 3 basic rules of class initialization:
751 | 1. Every class must have a designated initializer, if this class inherits from another, the designated initializer is responsible for calling the designated initializer of its immediate superclass.
752 | 2. Classes can have any number of convenience initializers, a convenience initializer must call another initializer from the same class, whether it is a designated initializer or another conveniences initializer.
753 | 3. Convenience initializers must ultimately call a designated initializer.
754 |
755 | ## How should one handle errors in Swift?
756 | The method for handling errors in Swift differ a bit from Objective-C. In Swift, it's possible to declare that a function throws an error. It is, therefore, the caller's responsibility to handle the error or propagate it. This is similar to how Java handles the situation.
757 |
758 | You simply declare that a function can throw an error by appending the throws keyword to the function name. Any function that calls such a method must call it from a try block.
759 |
760 | ```swift
761 | func canThrowErrors() throws -> String
762 |
763 | //How to call a method that throws an error
764 | try canThrowErrors()
765 |
766 | //Or specify it as an optional
767 | let maybe = try? canThrowErrors()
768 | ```
769 |
770 | ## What are benefits of Guard?
771 | There are two big benefits to guard. One is avoiding the pyramid of doom, as others have mentioned — lots of annoying if let statements nested inside each other moving further and further to the right. The other benefit is provide an early exit out of the function using break or using return.
772 |
773 |
774 | ## When applied to strings, what’s the complexity of the countElements function and why?
775 | Comments: The String struct doesn’t provide a count or length property or method to count the number of characters it contains. Instead a global countElements() function is available.
776 |
777 |
778 | Solution: Swift strings support extended grapheme clusters. Each character stored in a string is a sequence of one or more unicode scalars that, when combined, produce a single human readable character. Since different characters can require different amounts of memory, and considering that an extreme grapheme cluster must be accessed sequentially in order to determine which character it represents, it’s not possible to know the number of characters contained in a string upfront, without traversing the entire string. For that reason, the complexity of the countElements function is O(n).
779 |
780 | ## In Swift enumerations, what’s the difference between raw values and associated values?
781 | Raw values are used to associate constant (literal) values to enum cases. The value type is part of the enum type, and each enum case must specify a unique raw value (duplicate values are not allowed).
782 |
783 | The following example shows an enum with raw values of type Int:
784 |
785 | ```swift
786 | enum IntEnum : Int {
787 | case ONE = 1
788 | case TWO = 2
789 | case THREE = 3
790 | }
791 | ```
792 | An enum value can be converted to its raw value by using the rawValue property:
793 |
794 | ```swift
795 | var enumVar: IntEnum = IntEnum.TWO
796 | var rawValue: Int = enumVar.rawValue
797 | ```
798 | A raw value can be converted to an enum instance by using a dedicated initializer:
799 |
800 | ```swift
801 | var enumVar: IntEnum? = IntEnum(rawValue: 1)
802 | ```
803 | Associated values are used to associate arbitrary data to a specific enum case. Each enum case can have zero or more associated values, declared as a tuple in the case definition:
804 |
805 | ```swift
806 | enum AssociatedEnum {
807 | case EMPTY
808 | case WITH_INT(value: Int)
809 | case WITH_TUPLE(value: Int, text: String, data: [Float])
810 | }
811 | ```
812 |
813 | Whereas the type(s) associated to a case are part of the enum declaration, the associated value(s) are instance specific, meaning that an enum case can have different associated values for different enum instances.
814 |
815 | ## Swift Transforming Array functions
816 | → map and flatMap— how to transform element.
817 | → filter— should an element be included?
818 | → reduce— how to fold an element into an aggregate value
819 | → sort and lexicographicCompare—in what order should two elements come?
820 | → indexOf and contains—does this element match?
821 | → minElement and maxElement—which is the min/max of two elements?
822 | → elementsEqual and startsWith—are two elements equivalent?
823 | → split—is this element a separator?
824 |
825 | ## What is defer?
826 | defer keyword provides a safe and easy way to declare a block that will be executed only when execution leaves the current scope.
827 |
828 | Defer is usually used to cleanup the code after execution. This might involve deallocating container, releasing memory or close the file or network handle. When put into the routine, code inside defer block is last to execute before routine exits. Routine in this case could refer to a function. Sometimes when function returns there are hanging threads, incomplete operation which needs to cleanup. Instead of having them scattered across function, we can group them together and put in the defer block. When function exits, cleanup code in the defer gets executed.
829 |
830 | ## Extensions
831 | Extensions add new functionality to an existing class, structure, enumeration, or protocol type. This includes the ability to extend types for which you do not have access to the original source code. Extensions are similar to categories in Objective-C
832 |
833 | Extensions in Swift can:
834 | - Add computed instance properties and computed type properties
835 | - Define instance methods and type methods
836 | - Provide new initializers
837 | - Define subscripts
838 | - Define and use new nested types
839 | - Make an existing type conform to a protocol
840 |
841 | ## What is the difference Any and AnyObject?
842 | According to Apple’s Swift documentation:
843 | Any can represent an instance of any type at all, including function types and optional types.
844 | AnyObject can represent an instance of any class type.
845 |
846 | ## How will you make property’s getter available, but the property is settable only from within code in swift?
847 |
848 | The example below shows a version of the TrackedString structure in which the structure is defined with an explicit access level of public. The structure’s members (including the numberOfEdits property) therefore have an internal access level by default. You can make the structure’s numberOfEdits property getter public, and its property setter private, by combining the public and private(set) access-level modifiers:
849 |
850 |
851 |
852 | ## Property Wrappers
853 |
854 | A property wrapper adds a layer of separation between code that manages how a property is stored and the code that defines a property. For example, if you have properties that provide thread-safety checks or store their underlying data in a database, you have to write that code on every property. When you use a property wrapper, you write the management code once when you define the wrapper, and then reuse that management code by applying it to multiple properties.
855 |
856 | To define a property wrapper, you make a structure, enumeration, or class that defines a wrappedValue property. In the code below, the TwelveOrLess structure ensures that the value it wraps always contains a number less than or equal to 12. If you ask it to store a larger number, it stores 12 instead.
857 |
858 | ```swift
859 | @propertyWrapper
860 | struct TwelveOrLess {
861 | private var number: Int
862 | init() { self.number = 0 }
863 | var wrappedValue: Int {
864 | get { return number }
865 | set { number = min(newValue, 12) }
866 | }
867 | }
868 | ```
869 | The setter ensures that new values are less than 12, and the getter returns the stored value.
870 |
871 | ## Objective-C
872 |
873 | ## What is the difference between _ vs self. in Objective-C?
874 |
875 | You typically use either when accessing a property in Objective-C. When you use _, you're referencing the actual instance variable directly. You should avoid this. Instead, you should use self. to ensure that any getter/setter actions are honored.
876 |
877 | In the case that you would write your own setter method, using _ would not call that setter method. Using self. on the property, however, would call the setter method you implemented.
878 |
879 |
880 | ## What are blocks in Objective-C?
881 |
882 | Blocks are a language-level feature of Objective (C and C++ too). They are objects that allow you to create distinct segments of code that can be passed around to methods or functions as if they were values. This means that a block is capable of being added to collections such as NSArray or NSDictionary. Blocks are also able to take arguments and return values similar to methods and functions.
883 |
884 | The syntax to define a block literal uses the caret symbol(^):
885 |
886 | ```
887 |
888 | ^{
889 | NSLog(@"This is an example of a block")
890 | }
891 |
892 | ```
893 |
894 | ## Please explain Method Swizzling
895 |
896 | Method swizzling allows the implementation of an existing selector to be switched at runtime for a different implementation in a classes dispatch table. Swizzling allows you to write code that can be executed before and/or after the original method. For example perhaps to track the time method execution took, or to insert log statements.
897 |
898 | ```objectivec
899 | #import "UIViewController+Log.h"
900 | @implementation UIViewController (Log)
901 | + (void)load {
902 | static dispatch_once_t once_token;
903 | dispatch_once(&once_token, ^{
904 | SEL viewWillAppearSelector = @selector(viewDidAppear:);
905 | SEL viewWillAppearLoggerSelector = @selector(log_viewDidAppear:);
906 | Method originalMethod = class_getInstanceMethod(self, viewWillAppearSelector);
907 | Method extendedMethod = class_getInstanceMethod(self, viewWillAppearLoggerSelector);
908 | method_exchangeImplementations(originalMethod, extendedMethod);
909 | });
910 | }
911 | - (void) log_viewDidAppear:(BOOL)animated {
912 | [self log_viewDidAppear:animated];
913 | NSLog(@"viewDidAppear executed for %@", [self class]);
914 | }
915 | @end
916 | ```
917 | ## "Strong” and “weak” references
918 | By default, any variable that points to another object does so with what is referred to as a “strong” reference. A retain cycle occurs when two or more objects have reciprocal strong references (i.e., strong references to each other). Any such objects will never be destroyed by ARC (iOS’ Automatic Reference Counting). Even if every other object in the application releases ownership of these objects, these objects (and, in turn, any objects that reference them) will continue to exist by virtue of those mutual strong references. This therefore results in a memory leak.
919 |
920 | Reciprocal strong references between objects should therefore be avoided to the extent possible. However, when they are necessary, a way to avoid this type of memory leak is to employ weak references. Declaring one of the two references as weak will break the retain cycle and thereby avoid the memory leak.
921 |
922 | To decide which of the two references should be weak, think of the objects in the retain cycle as being in a parent-child relationship. In this relationship, the parent should maintain a strong reference (i.e., ownership of) its child, but the child should not maintain maintain a strong reference (i.e., ownership of) its parent.
923 |
924 | For example, if you have Employer and Employee objects, which reference one another, you would most likely want to maintain a strong reference from the Employer to the Employee object, but have a weak reference from the Employee to the Employer.
925 |
926 | ## What is the difference strong, weak, readonly and copy?
927 | - `Strong` means that the reference count will be increased and the reference to it will be maintained through the life of the object
928 | - `Weak` means that we are pointing to an object but not increasing its reference count. It’s often used when creating a parent child relationship. The parent has a strong reference to the child but the child only has a weak reference to the parent.
929 | - `Readonly`, we can set the property initially but then it can’t be changed.
930 | - `Copy` means that we’re copying the value of the object when it’s created. Also prevents its value from changing.
931 |
932 | ## What is dynamic in Objective-C?
933 | `@dynamic` used to delegate the responsibility of implementing the accessors.
934 | Dynamic for properties means that it setters and getters will be created manually and/or at runtime.
935 |
936 | ## What is made up of NSError object?
937 | There are three parts of NSError object a domain, an error code, and a user info dictionary. The domain is a string that identifies what categories of errors this error is coming from.
938 |
939 | # General
940 |
941 | ## What is the difference in functional programming and OOPS?
942 |
943 |
944 | ## HTTP request types
945 | An HTTP request is a class consisting of HTTP style requests, request lines, request methods, request URL, header fields, and body content. The most common methods that are used by a client in an HTTP request are as follows:
946 |
947 | 1) GET:- Used when the client is requesting a resource on the Web server.
948 |
949 | 2) HEAD:- Used when the client is requesting some information about a resource but not requesting the resource itself.
950 |
951 | 3) POST:- Used when the client is sending information or data to the server—for example, filling out an online form (i.e. Sends a large amount of complex data to the Web Server).
952 |
953 | 4) PUT:- Used when the client is sending a replacement document or uploading a new document to the Web server under the request URL.
954 |
955 | # Communication protocols
956 |
957 | ## Network socket
958 |
959 | __Network socket__ is an internal endpoint for sending or receiving data at a single node in a computer network. Concretely, it is a representation of this endpoint in networking software (protocol stack), such as an entry in a table (listing communication protocol, destination, status, etc.), and is a form of system resource.
960 | The term "socket" is analogous to physical female connectors, communication between two nodes through a channel being visualized as a cable with two male connectors plugging into sockets at each node. Similarly, the term "port" (another term for a female connector) is used for external endpoints at a node, and the term "socket" is also used for an internal endpoint of local inter-process communication (IPC) (not over a network). However, the analogy is strained, as network communication need not be one-to-one or have a channel.
961 |
962 | ## WebSocket
963 |
964 | __WebSocket__ is a computer communications protocol, providing full-duplex communication channels over a single TCP connection. The WebSocket protocol was standardized by the IETF as RFC 6455 in 2011, and the WebSocket API in Web IDL is being standardized by the W3C.
965 | WebSocket is a different TCP protocol from HTTP. Both protocols are located at layer 7 in the OSI model and, as such, depend on TCP at layer 4. Although they are different, RFC 6455 states that WebSocket "is designed to work over HTTP ports 80 and 443 as well as to support HTTP proxies and intermediaries" thus making it compatible with the HTTP protocol. To achieve compability, the WebSocket handshake uses the HTTP Upgrade header[1] to change from the HTTP protocol to the WebSocket protocol.
966 | The WebSocket protocol enables interaction between a browser and a web server with lower overheads, facilitating real-time data transfer from and to the server. This is made possible by providing a standardized way for the server to send content to the browser without being solicited by the client, and allowing for messages to be passed back and forth while keeping the connection open. In this way, a two-way (bi-directional) ongoing conversation can take place between a browser and the server. The communications are done over TCP port number 80 (or 443 in the case of TLS-encrypted connections), which is of benefit for those environments which block non-web Internet connections using a firewall. Similar two-way browser-server communications have been achieved in non-standardized ways using stopgap technologies such as Comet.
967 |
968 | ## TCP Stream Socket
969 | Is much more commonly used, as it provides the framework for a complete, structured "conversation" to occur between the two endpoints. TCP connections provide a means to ensure the message was received, and guarantees that packets are received in order. TCP is used by protocols including HTTP, FTP, and others where data must be reliably sent and received in order. To keep track of the ordering of packets, TCP employs a sequence number, which identifies the sequence of each packet. This not only keeps your conversation in order, but also adds a basic level of protection against some forms of spoofing (data forgery by a malicious party).
970 |
971 | * Dedicated & point-to-point channel between server and client.
972 | * Reliable and Lossless.
973 | * Data sent/received in the similar order.
974 | * Long time for recovering lost/mistaken data
975 | * Web, SSH, FTP, TELNET, SMTP, IMAP/POP
976 |
977 | ## UDP Datagram Socket
978 |
979 | Is used for sending short messages called datagrams to the recipient. Datagrams are single packets of data that are sent and received without any "return postage." There is no guarantee that the recipient will receive a particular packet, and multiple packets may be received out of order. Datagrams are generally thought of as unreliable, in the same way that a carrier pigeon can be unreliable. This form of communication is used for sending short query/response-type messages that do not require authentication, such as DNS (name resolution) lookups, as well as by some protocols where lost packets are irrelevant; such as live video streams and online multiplayer games, where an interruption can be ignored.
980 |
981 | * No dedicated & point-to-point channel between server and client.
982 | * Not 100% reliable and may lose data.
983 | * Data sent/received order might not be the same
984 | * Don't care or rapid recovering lost/mistaken data
985 | * Tunneling/VPN (lost packets are ok - the tunneled protocol takes care of it)
986 | * Media streaming
987 | * Games that don't care if you get every update
988 | * Local broadcast mechanisms (same application running on different machines "discovering" each other)
989 | ***
990 | ```c
991 | CFSocketRef CFSocketCreate (
992 | CFAllocatorRef allocator,
993 | SInt32 protocolFamily,
994 | SInt32 socketType,
995 | SInt32 protocol,
996 | CFOptionFlags callBackTypes,
997 | CFSocketCallBack callout,
998 | const CFSocketContext *context
999 | );
1000 | ```
1001 | ## CFStream
1002 |
1003 | Socket streams provide an easy interface for reading and writing data to or from a socket. Each socket can be bound to a read and write stream, allowing for synchronous or asynchronous communication. Streams encapsulate most of the work needed for reading and writing byte streams, and replace the traditional `send()` and `recv()` functions used in C. Two different stream objects are used with sockets: `CFReadStream` and `CFWriteStream`
1004 |
1005 | ## NSStream
1006 |
1007 | __`NSStream`__ is an abstract class that defines the fundamental interface and properties for all stream objects. `NSInputStream` and `NSOutputStream` are subclasses of `NSStream` and implement default input-stream and output-stream behavior. `NSStream` is built on the `CFStream` layer of Core Foundation. This close relationship means that the concrete subclasses of `NSStream`, `NSOutputStream` and `NSInputStream`, are toll-free bridged with their Core Foundation counterparts `CFWriteStream` and `CFReadStream`. Although there are strong similarities between the Cocoa and Core Foundation stream APIs, their implementations are not exactly coincident. The Cocoa stream classes use the delegation model for asynchronous behavior (assuming run-loop scheduling) while Core Foundation uses client callbacks. Despite their strong similarities, __`NSStream` does give you a major advantage over `CFStream`. Because of its Objective-C underpinnings, it is extensible.__ You can subclass `NSStream`, `NSInputStream`, or `NSOutputStream` to customize stream attributes and behavior. For example, you could create an input stream that maintains statistics on the bytes it reads; or you could make a `NSStream` subclass whose instances can seek through their stream, putting back bytes that have been read. `NSStream` has its own set of required overrides, as do `NSInputStream` and `NSOutputStream`.
1008 |
1009 | ## REST
1010 | An architectural style called REST (Representational State Transfer) advocates that web applications should use HTTP as it was originally envisioned. Lookups should use GET requests. PUT, POST, and DELETE requests should be used for *mutation, creation, and deletion respectively *.
1011 |
1012 | REST proponents tend to favor URLs, such as
1013 |
1014 | server.com/catalog/thing/1723
1015 | but the REST architecture does not require these “pretty URLs”. A GET request with a parameter
1016 |
1017 | server.com/catalog?thing=1723
1018 | is every bit as RESTful.
1019 |
1020 | GET requests should never be used for updating information. For example, a GET request for adding an item to a cart
1021 |
1022 | server.com/addToCart?cart=314159&thing=1723
1023 |
1024 | would not be appropriate. GET requests should be idempotent. That is, issuing a request twice should be no different from issuing it once. That’s what makes the requests cacheable. An “add to cart” request is not idempotent—issuing it twice adds two copies of the item to the cart. A POST request is clearly appropriate in this context. Thus, even a RESTful web application needs its share of POST requests.
1025 |
1026 | ## SOAP
1027 |
1028 | SOAP (originally Simple Object Access Protocol) is a protocol specification for exchanging structured information in the implementation of web services in computer networks. Its purpose is to induce extensibility, neutrality and independence. It uses XML Information Set for its message format, and relies on application layer protocols, most often Hypertext Transfer Protocol (HTTP) or Simple Mail Transfer Protocol (SMTP), for message negotiation and transmission.
1029 |
1030 | SOAP allows processes running on disparate operating systems (such as Windows and Linux) to communicate using Extensible Markup Language (XML). Since Web protocols like HTTP are installed and running on all operating systems, SOAP allows clients to invoke web services and receive responses independent of language and platforms.
1031 |
1032 | ## Deep and shallow copy
1033 | There are two kinds of object copying: shallow copies and deep copies. The normal copy is a shallow copy that produces a new collection that shares ownership of the objects with the original. Deep copies create new objects from the originals and add those to the new collection.
1034 |
1035 | ## What is the difference between functions and methods in Swift?
1036 |
1037 | Both are functions in the same terms any programmer usually knows of it. But functions are globally scoped while methods belong to a certain type.
1038 |
1039 | ## Protocol Oriented Programming
1040 |
1041 | Protocol-Oriented Programming is a new programming paradigm ushered in by Swift 2.0. In the Protocol-Oriented approach, we start designing our system by defining protocols. We rely on new concepts: protocol extensions, protocol inheritance, and protocol compositions. The paradigm also changes how we view semantics. In Swift, value types are preferred over classes. However, object-oriented concepts don’t work well with structs and enums: a struct cannot inherit from another struct, neither can an enum inherit from another enum. So inheritancefa - one of the fundamental object-oriented concepts - cannot be applied to value types. On the other hand, value types can inherit from protocols, even multiple protocols. Thus, with POP, value types have become first class citizens in Swift.
1042 |
1043 | __Protocol Extensions__
1044 |
1045 | You can extend a protocol and provide default implementation for methods, computed properties, subscripts and convenience initializers.
1046 |
1047 | __Protocol Inheritance__
1048 |
1049 | A protocol can inherit from other protocols and then add further requirements on top of the requirements it inherits.
1050 |
1051 | __Protocol Composition__
1052 |
1053 | Swift types can adopt multiple protocols.
1054 |
1055 | # Data
1056 |
1057 | ## Managed object context and the functionality that it provides
1058 | A managed object context (represented by an instance of NSManagedObjectContext) is basically a temporary “scratch pad” in an application for a (presumably) related collection of objects. These objects collectively represent an internally consistent view of one or more persistent stores. A single managed object instance exists in one and only one context, but multiple copies of an object can exist in different contexts.
1059 |
1060 | You can think of a managed object context as an intelligent scratch pad. When you fetch objects from a persistent store, you bring temporary copies onto the scratch pad where they form an object graph (or a collection of object graphs). You can then modify those objects however you like. Unless you actually save those changes, though, the persistent store remains unchanged.
1061 |
1062 | Key functionality provided by a managed object context includes:
1063 |
1064 | Life-cycle management. The context provides validation, inverse relationship handling, and undo/redo. Through a context you can retrieve or “fetch” objects from a persistent store, make changes to those objects, and then either discard the changes or commit them back to the persistent store. The context is responsible for watching for changes in its objects and maintains an undo manager so you can have finer-grained control over undo and redo. You can insert new objects and delete ones you have fetched, and commit these modifications to the persistent store.
1065 | Notifications. A context posts notifications at various points which can optionally be monitored elsewhere in your application.
1066 | Concurrency. Core Data uses thread (or serialized queue) confinement to protect managed objects and managed object contexts. In OS X v10.7 and later and iOS v5.0 and later, when you create a context you can specify the concurrency pattern with which you will use it using initWithConcurrencyType:
1067 |
1068 | ## How does NSManagedObjectContext work?
1069 | `Managed object context` exists for three reasons: life-cycle management, notifications, and concurrency. It allows the developer to fetch an object from a persistent store and make the necessary modifications before deciding whether to discard or commit these changes back to the persistent store. The managed object context tracks these changes and allows the developer to undo and redo changes.
1070 |
1071 | ## NSFetchedResultsController
1072 | `NSFetchedResultsController` is a controller, but it’s not a view controller. It has no user interface. Its purpose is to make developers’ lives easier by abstracting away much of the code needed to synchronize a table view with a data source backed by Core Data.
1073 | Set up an NSFetchedResultsController correctly, and your table will mimic its data source without you have to write more than a few lines of code.
1074 |
1075 | ## NSPersistentContainer
1076 | The persistent container creates and returns a container, having loaded the store for the application to it. This property is optional since there are legitimate error conditions that could cause the creation of the store to fail.
1077 |
1078 | ## What is NSFetchRequest?
1079 | `NSFetchRequest` is the class responsible for fetching from Core Data. Fetch requests are both powerful and flexible. You can use fetch requests to fetch a set of objects meeting the provided criteria, individual values and more.
1080 |
1081 | # Concurrency
1082 |
1083 | ## Different ways of achieving concurrency in Mac OS and iOS
1084 | There are basically three ways of achieving concurrency in iOS:
1085 | 1. threads
1086 | 2. GCD
1087 | 3. NSOperationQueue
1088 |
1089 | The disadvantage of threads is that they relegate the burden of creating a scalable solution to the developer. You have to decide how many threads to create and adjust that number dynamically as conditions change. Also, the application assumes most of the costs associated with creating and maintaining the threads it uses.
1090 |
1091 | OS X and iOS therefore prefer to take an asynchronous design approach to solving the concurrency problem rather than relying on threads.
1092 |
1093 | One of the technologies for starting tasks asynchronously is Grand Central Dispatch (GCD) that relegates thread management down to the system level. All the developer has to do is define the tasks to be executed and add them to the appropriate dispatch queue. GCD takes care of creating the needed threads and scheduling tasks to run on those threads.
1094 |
1095 | All dispatch queues are first-in, first-out (FIFO) data structures, so tasks are always started in the same order that they are added.
1096 |
1097 | An operation queue is the Cocoa equivalent of a concurrent dispatch queue and is implemented by the NSOperationQueue class. Unlike dispatch queues, operation queues are not limited to executing tasks in FIFO order and support the creation of complex execution-order graphs for your tasks.
1098 |
1099 | ## POSIX Threads
1100 | Usually referred to as Pthreads, is a POSIX standard for threads defines an API for creating and manipulating threads. Pthreads defines a set of C programming language types, functions and constants. It is implemented with a pthread.h header and a thread library. There are around 100 Pthreads procedures, all prefixed `pthread_` and they can be categorized into four groups:
1101 |
1102 | * Thread management - creating, joining threads etc.
1103 | * Mutexes
1104 | * Condition variables
1105 | * Synchronization between threads using read/write locks and barriers
1106 |
1107 | Implementations of the API are available on many Unix-like POSIX-conformant operating systems such as FreeBSD, NetBSD, OpenBSD, GNU/Linux, Mac OS X and Solaris. DR-DOS and Microsoft Windows implementations also exist.
1108 | Use POSIX calls if cross-platform portability is required. If you are writing networking code that runs exclusively in OS X and iOS, you should generally avoid POSIX networking calls, because they are harder to work with than higher-level APIs. However, if you are writing networking code that must be shared with other platforms, you can use the POSIX networking APIs so that you can use the same code everywhere.
1109 |
1110 | ## NSThread
1111 |
1112 | A simple Objective-C wrapper around pthreads. This makes the code look more familiar in a Cocoa environment. It is a relatively lightweight way to implement multiple paths of execution inside of an application. For example, you can define a thread as a subclass of `NSThread`, which encapsulates the code you want to run in the background.
1113 |
1114 | Though Operation queues is the preferred way to perform tasks concurrently, depending on application there may still be times when you need to create custom threads.
1115 | Threads are still a good way to implement code that must run in real time.
1116 | Use threads for specific tasks that cannot be implemented in any other way.
1117 | If you need more predictable behavior from code running in the background, threads may still offer a better alternative.
1118 |
1119 | _Inter-thread Communication_
1120 | * Direct messaging
1121 | * Global variables, shared memory, and objects
1122 | * Conditions
1123 | * Run loop sources
1124 | * Ports and sockets
1125 | * Message queues
1126 | * Cocoa distributed objects
1127 | __Dispatch Queue__
1128 |
1129 | Dispatch queues are a C-based mechanism for __executing custom tasks__. A dispatch queue executes tasks either serially or concurrently but __always in a FIFO order__. A serial dispatch queue runs only one task at a time, waiting until that task is complete before dequeuing and starting a new one. By contrast, a concurrent dispatch queue starts as many tasks as it can without waiting for already started tasks to finish.
1130 |
1131 | - Serial
1132 |
1133 | Serial queues (also known as private dispatch queues) execute one task at a time in the order in which they are added to the queue. The currently executing task runs on a distinct thread (which can vary from task to task) that is managed by the dispatch queue. Serial queues are often used to synchronize access to a specific resource.
1134 | You can create as many serial queues as you need, and each queue operates concurrently with respect to all other queues. In other words, if you create four serial queues, each queue executes only one task at a time but up to four tasks could still execute concurrently, one from each queue.
1135 |
1136 | - Concurrent
1137 |
1138 | Concurrent queues (also known as a type of global dispatch queue) execute one or more tasks concurrently, but tasks are still started in the order in which they were added to the queue. The currently executing tasks run on distinct threads that are managed by the dispatch queue. The exact number of tasks executing at any given point is variable and depends on system conditions.
1139 | In iOS 5 and later, you can create concurrent dispatch queues yourself by specifying `DISPATCH_QUEUE_CONCURRENT` as the queue type. In addition, there are four predefined global concurrent queues for your application to use.
1140 |
1141 | - Main dispatch queue
1142 |
1143 | The main dispatch queue is a globally available serial queue that executes tasks on the application’s main thread. This queue works with the application’s run loop (if one is present) to interleave the execution of queued tasks with the execution of other event sources attached to the run loop. Because it runs on your application’s main thread, the main queue is often used as a key synchronization point for an application. Although you do not need to create the main dispatch queue, you do need to make sure your application drains it appropriately.
1144 |
1145 | __Dispatch Source__
1146 |
1147 | Dispatch sources are a C-based mechanism __for processing specific types of system events asynchronously__. A dispatch source encapsulates information about a particular type of system event and submits a specific block object or function to a dispatch queue whenever that event occurs. You can use dispatch sources to monitor the following types of system events:
1148 |
1149 | * Timers
1150 | * Signal handlers
1151 | * Descriptor-related events
1152 | * Process-related events
1153 | * Mach port events
1154 | * Custom events that you trigger
1155 |
1156 | - async - concurrent: the code runs on a background thread. Control returns immediately to the main thread (and UI). The block can't assume that it's the only block running on that queue
1157 | - async - serial: the code runs on a background thread. Control returns immediately to the main thread. The block can assume that it's the only block running on that queue
1158 | - sync - concurrent: the code runs on a background thread but the main thread waits for it to finish, blocking any updates to the UI. The block can't assume that it's the only block running on that queue (I could have added another block using async a few seconds previously)
1159 | - sync - serial: the code runs on a background thread but the main thread waits for it to finish, blocking any updates to the UI. The block can assume that it's the only block running on that queue
1160 |
1161 | ## Quality of Service (QoS)
1162 |
1163 | The QoS classes are:
1164 | * User-interactive: This represents tasks that need to be done immediately in order to provide a nice user experience. Use it for UI updates, event handling and small workloads that require low latency. The total amount of work done in this class during the execution of your app should be small. This should run on the main thread.
1165 | * User-initiated: The represents tasks that are initiated from the UI and can be performed asynchronously. It should be used when the user is waiting for immediate results, and for tasks required to continue user interaction. This will get mapped into the high priority global queue.
1166 | * Utility: This represents long-running tasks, typically with a user-visible progress indicator. Use it for computations, I/O, networking, continous data feeds and similar tasks. This class is designed to be energy efficient. This will get mapped into the low priority global queue.
1167 | * Background: This represents tasks that the user is not directly aware of. Use it for prefetching, maintenance, and other tasks that don’t require user interaction and aren’t time-sensitive. This will get mapped into the background priority global queue.
1168 | ```swift
1169 | DispatchQueue.global(attributes: [.qosDefault]).async {
1170 | // Background thread
1171 | DispatchQueue.main.async(execute: {
1172 | // UI Updates
1173 | })
1174 | }
1175 | ```
1176 |
1177 | ## NSOperationQueue
1178 | Operation queues are a Cocoa abstraction of the queue model exposed by GCD. While GCD offers more low-level control, operation queues implement several convenient features on top of it, which often makes it the best and safest choice for application developers. The `NSOperationQueue` class has two different types of queues: the main queue and custom queues. The main queue runs on the main thread, and custom queues are processed in the background. In any case, the tasks which are processed by these queues are represented as subclasses of `NSOperation`. Whereas dispatch queues always execute tasks in first-in, first-out order, operation queues __take other factors into account when determining the execution order of tasks__. Primary among these factors is whether a given task depends on the completion of other tasks. You configure dependencies when defining your tasks and can use them to create complex execution-order graphs for your tasks. Because the `NSOperation` class is essentially an abstract base class, you typically define custom subclasses to perform your tasks. However, the Foundation framework does include some concrete subclasses that you can create and use as is to perform tasks.
1179 |
1180 | `NSBlockOperation` exectues a block. `NSInvocationOperation` executes a `NSInvocation` (or a method defined by target, selector, object). `NSOperation` must be subclassed, it offers the most flexibility but requires the most code. `NSBlockOperation` and `NSInvocationOperation` are both subclasses of `NSOperation`. They are provided by the system so you don't have to create a new subclass for simple tasks. Using `NSBlockOperation` and `NSInvocationOperation` should be enough for most tasks.
1181 |
1182 | After an operation begins executing, it continues performing its task until it is finished or until your code explicitly cancels the operation. Cancellation can occur at any time, even before an operation begins executing. Although the NSOperation class provides a way for clients to cancel an operation, recognizing the cancellation event is voluntary by necessity. If an operation were terminated outright, there might not be a way to reclaim resources that had been allocated. As a result, operation objects are expected to check for cancellation events and to exit gracefully when they occur in the middle of the operation.
1183 |
1184 | ## Cancel NSOperation problem
1185 |
1186 | Canceling the operation will only update its isCancelled property to YES.
1187 | To be able to cancel the operation, you should do the following:
1188 |
1189 | ```objectivec
1190 | NSBlockOperation * op = [NSBlockOperation new];
1191 | __weak NSBlockOperation * weakOp = op; // Use a weak reference to avoid a retain cycle
1192 | [op addExecutionBlock:^{
1193 | // Put this code between whenever you want to allow an operation to cancel
1194 | // For example: Inside a loop, before a large calculation, before saving/updating data or UI, etc.
1195 | if (weakOp.isCancelled) return;
1196 |
1197 | // Do something..
1198 | ];
1199 | ```
1200 |
1201 | ## GCD
1202 | With GCD you don’t interact with threads directly anymore. Instead you add blocks of code to queues, and GCD manages a thread pool behind the scenes. GCD decides on which particular thread your code blocks are going to be executed on, and it manages these threads according to the available system resources. This alleviates the problem of too many threads being created, because the threads are now centrally managed and abstracted away from application developers. The other important change with GCD is that you as a developer think about work items in a queue rather than threads. This new mental model of concurrency is easier to work with. GCD exposes five different queues: the main queue running on the main thread, three background queues with different priorities, and one background queue with an even lower priority, which is I/O throttled. Furthermore, you can create custom queues, which can either be serial or concurrent queues. While custom queues are a powerful abstraction, all blocks you schedule on them will ultimately trickle down to one of the system’s global queues and its thread pool(s).
1203 |
1204 | ## What is DispatchGroup?
1205 | `DispatchGroup` allows for aggregate synchronization of work. We can use them to submit multiple different work items and track when they all complete, even though they might run on different queues. This behavior can be helpful when progress can’t be made until all of the specified tasks are complete.
1206 |
1207 | ## Synchronized
1208 | The `@synchronized` directive is a convenient way to create mutex locks on the fly in Objective-C code.
1209 |
1210 | `Synchronized` guarantees that only one thread can be executing that code in the block at any given time.
1211 |
1212 | Syntax:
1213 | ```objectivec
1214 | @synchronized(key)
1215 | {
1216 | // thread-safe code
1217 | }
1218 | ```
1219 |
1220 | Example:
1221 | ```objectivec
1222 | -(void)AppendExisting:(NSString*)val
1223 | {
1224 | @synchronized (oldValue) {
1225 | [oldValue stringByAppendingFormat:@"-%@",val];
1226 | }
1227 | }
1228 | ```
1229 | Now the above code is perfectly thread safe..Now Multiple threads can change the value.
1230 |
1231 |
1232 | ## What is the difference between Synchronous & Asynchronous task?
1233 | `Synchronous`: waits until the task has completed
1234 | `Asynchronous`: completes a task in background and can notify you when complete
1235 |
1236 | ## Semaphore
1237 |
1238 | _Is the number of free identical toilet keys. Example, say we have four toilets with identical locks and keys. The semaphore count - the count of keys - is set to 4 at beginning (all four toilets are free), then the count value is decremented as people are coming in. If all toilets are full, ie. there are no free keys left, the semaphore count is 0. Now, when eq. one person leaves the toilet, semaphore is increased to 1 (one free key), and given to the next person in the queue._
1239 |
1240 | Variable or abstract data type used to control access to a common resource by multiple processes in a concurrent system. A trivial semaphore is a plain variable that is changed (for example, incremented or decremented, or toggled) depending on programmer-defined conditions. The variable is then used as a condition to control access to some system resource. A useful way to think of a semaphore as used in the real-world systems is as a record of how many units of a particular resource are available, coupled with operations to adjust that record safely (i.e. to avoid race conditions) as units are required or become free, and, if necessary, wait until a unit of the resource becomes available. Semaphores are a useful tool in the prevention of race conditions; however, their use is by no means a guarantee that a program is free from these problems. Semaphores which allow an arbitrary resource count are called __counting semaphores__, while semaphores which are restricted to the values 0 and 1 (or locked/unlocked, unavailable/available) are called __binary semaphores__ and are used to implement locks.
1241 |
1242 | ## Lock
1243 | Mechanism for enforcing limits on access to a resource in an environment where there are many threads of execution. A lock is designed to enforce a mutual exclusion concurrency control policy.
1244 |
1245 | ## Mutex
1246 | _Is a key to a toilet. One person can have the key - occupy the toilet - at the time. When finished, the person gives (frees) the key to the next person in the queue._
1247 |
1248 | ## Semaphore vs Mutex vs Lock
1249 |
1250 | __Explanation 1__
1251 |
1252 | A mutex is essentially the same thing as a binary semaphore and sometimes uses the same basic implementation. The differences between them are in how they are used. While a binary semaphore may be used as a mutex, a mutex is a more specific use-case, in that only the thread that locked the mutex is supposed to unlock it.
1253 | A mutex is a synchronization object. You acquire a lock on a mutex at the beginning of a section of code, and release it at the end, in order to ensure that no other thread is accessing the same data at the same time. A mutex typically has a lifetime equal to that of the data it is protecting, and that one mutex is accessed by multiple threads.
1254 | A lock object is an object that encapsulates that lock. When the object is constructed it acquires the lock on the mutex. When it is destructed the lock is released. You typically create a new lock object for every access to the shared data.
1255 |
1256 | __Explanation 2__
1257 |
1258 | A mutex is an object which can be locked. A lock is the object which maintains the lock. To create a lock, you need to pass it a mutex.
1259 |
--------------------------------------------------------------------------------
/Resources/Main.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dashvlas/awesome-ios-interview/0092bb4f4ec5aa1fd67b690adb7b1fe47b7e28e9/Resources/Main.png
--------------------------------------------------------------------------------
/Resources/Preview.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dashvlas/awesome-ios-interview/0092bb4f4ec5aa1fd67b690adb7b1fe47b7e28e9/Resources/Preview.gif
--------------------------------------------------------------------------------
/Resources/Russian.md:
--------------------------------------------------------------------------------
1 | * [UIKit](#uikit)
2 | * [Bounds и Frame](#Чем-отличаются-bounds-и-frame)
3 | * [Когда bounds будет отлично от нуля?](#Когда-bounds-будет-отлично-от-нуля)
4 | * [Как работает UITableView?](#Как-работает-uitableview)
5 | * [Points и Pixels](#Разница-между-points-и-pixels)
6 | * [Как поймать неприятный лаг?](#Как-поймать-неприятный-лаг-На-что-обращать-внимание)
7 | * [Autolayout](#autolayout)
8 |
9 | * [SDK](#sdk)
10 | * [NSCoding, archiving](#nscoding-archiving)
11 | * [Создание архивов](#Создание-архивов)
12 | * [Чтение архивов](#Чтение-архивов)
13 | * [Как работают push-уведомления?](#Как-работают-push-уведомления)
14 | * [Memory warning](#memory-warning)
15 | * [Жизненный цикл приложения](#Жизненный-цикл-приложения)
16 | * [Жизненный цикл ViewController](#Жизненный-цикл-viewcontroller)
17 |
18 | * [Паттерны](#Паттерны)
19 | * [Observer](#observer)
20 | * [Singleton](#singleton)
21 | * [Минусы](#Минусы-singleton)
22 | * [Lazy initialization](#lazy-initialization)
23 | * [Достоинства](#Достоинства)
24 | * [Недостатки](#Недостатки)
25 | * [Пример](#Пример)
26 | * [Способы реализации паттерна Observer](#Способы-реализации-паттерна-observer)
27 | * [Factory Method](#factory-method)
28 | * [Responder chain](#responder-chain)
29 |
30 | * [Архитектура](#Архитектура)
31 | * [MVC](#mvc)
32 | * [Активная модель](#Активная-модель)
33 | * [Пассивная модель](#Пассивная-модель)
34 | * [MVVM](#mvvm)
35 | * [MVP](#mvp)
36 | * [Viper](#viper)
37 |
38 | * [ООП](#ООП)
39 | * [Киты ООП](#Киты-ООП)
40 | * [Плюсы и минусы ООП](#Плюсы-и-минусы-ООП)
41 | * [SOLID](#Что-такое-solid)
42 | * [Нарушение инкапсуляции](#Что-такое-нарушение-инкапсуляции)
43 | * [Понятия ОО-программирования в Objective-C](#Понятия-ОО-программирования-в-objective-c)
44 |
45 | * [Управление памятью](#Управление-памятью)
46 | * [Garbage Collector](#garbage-collector)
47 | * [ARC](#arc)
48 | * [Освобождение памяти в MRC](#Освобождение-памяти-в-mrc)
49 | * [Atomic
vs nonatomic
. Сеттер в MRC?](#atomic-vs-nonatomic-Переопределение-сеттера-в-mrc).
50 |
51 | * [Язык](#Язык)
52 | * [Различия isKindOfClass и isMemberOfClass](#Различия-iskindofclass-и-ismemberofclass)
53 | * [Когда лучше использовать категорию, а когда наследование?](#Когда-лучше-использовать-категорию-а-когда-наследование)
54 | * [Из чего состоит NSError?](#Из-чего-состоит-nserror)
55 | * [KVC](#kvc)
56 | * [Forward Invocation](#forward-invocation)
57 | * [Fast enumeration](#fast-enumeration)
58 | * [Чем объект Objective-C отличается от структуры С?](#Чем-объект-objective-c-отличается-от-структуры-С)
59 | * [Что такое runLoop, когда он используется?](#Что-такое-runloop-когда-он-используется)
60 | * [nil, Nil, NULL, NSNull](#nil-nil-null-nsnull)
61 | * [Протоколы](#Протоколы)
62 | * [Формальные протоколы](#Формальные-протоколы)
63 | * [Неформальные протоколы](#Неформальные-протоколы)
64 | * [Что такое @dynamic?](#Что-такое-dynamic)
65 | * [Тип id](#Тип-id)
66 | * [defer](#defer)
67 | * [Механизм сообщений](#Как-работает-механизм-сообщений)
68 | * [Приватные методы в Objective-C](#Приватные-методы-в-objective-c)
69 | * [Можно ли добавить ivar в категорию?](#Можно-ли-добавить-ivar-в-категорию)
70 | * [Что такое указатель isa? Для чего он нужен?](#Что-такое-указатель-isa-Для-чего-он-нужен)
71 | * [В чем отличие void* от id?](#В-чем-отличие-void-от-id)
72 | * [KVO](#kvo)
73 | * [Плюсы](#Плюсы)
74 | * [Недостатки](#Недостатки-1)
75 | * [Чем отличается include от import?](#Чем-отличается-include-от-import)
76 | * [Что такое селектор и как его вызвать?](#Что-такое-селектор-selector-Как-его-вызвать)
77 | * [Что такое замыкания и где их можно использовать?](#Что-такое-замыкания-и-где-их-можно-использовать)
78 | * [Что такое убегающие и неубегающие замыкания (escaping/nonescaping closures)?](#Что-такое-убегающие-и-неубегающие-замыкания-escaping-nonescaping-closures)
79 |
80 | * [Общие вопросы](#Общие-вопросы)
81 | * [Архитектура REST](#Архитектура-rest)
82 | * [Протоколы передачи данных](#Протоколы-передачи-данных)
83 | * [IP](#ip)
84 | * [TCP](#tcp)
85 | * [UDP](#udp)
86 | * [HTTP](#http)
87 | * [FTP](#ftp)
88 | * [Поверхностное и глубокое копирование](#Поверхностное-и-глубокое-копирование)
89 | * [Назначенный инициализатор](#Что-такое-назначенный-инициализатор)
90 | * [Виды запросов](#Виды-запросов)
91 | * [HEAD](#head)
92 | * [GET](#get)
93 | * [POST](#post)
94 | * [PUT](#put)
95 | * [URL & URI](#url-and-uri)
96 |
97 | * [БД](#БД)
98 | * [Типы хранилищ CoreData](#Какие-типы-хранилищ-поддерживает-coredata)
99 | * [Что такое ленивая загрузка? Что ее связывает с CoreData?](#Что-такое-ленивая-загрузка-Что-ее-связывает-с-coredata)
100 | * [Целесообразность использования CoreData](#Целесообразность-использования-coredata)
101 | * [Realm](#realm)
102 | * [Преимущества над другими БД](#Преимущества-над-другими-БД)
103 | * [SQLite](#sqlite)
104 | * [NSManagedObjectId](#Что-такое-nsmanagedobjectid)
105 | * [NSFetchedResultsController](#nsfetchedresultscontroller)
106 | * [NSManagedObjectContext](#Что-такое-контекст-managed-object-context)
107 | * [NSPersistentStoreCoordinator](#Что-такое-persistent-store-coordinator)
108 | * [Нюансы Core Data в разных потоках](#Какие-есть-нюансы-при-использовании-core-data-в-разных-потоках)
109 |
110 | * [Многопоточность](#Многопоточность)
111 | * [Runloop](#runloop)
112 | * [Многопоточность в iOS и macOS](#Способы-достижения-многопоточности-в-ios-и-macos)
113 | * [Deadlock](#Что-такое-deadlock)
114 | * [Livelock](#Что-такое-livelock)
115 | * [DispatchGroup](#Что-такое-dispatchgroup)
116 | * [Синхронные и асинхронные задачи](#Разница-между-синхронными-и-асинхронными-задачами-однопоточностью-и-многопоточностью)
117 | * [@synchronized](#Зачем-использовать-synchronized)
118 | * [Мьютекс](#Что-такое-мьютекс-mutex)
119 | * [Семафор](#Что-такое-семафор-semafor)
120 |
121 | * [Тестирование](#Тестирование)
122 | * [Unit-тесты](#unit-тесты)
123 | * [TDD](#tdd)
124 |
125 | * [Задания](#Задания)
126 | * [Какой метод вызовется: класса A или класса B?](#Какой-метод-вызовется-класса-a-или-класса-b)
127 | * [Что выведется в консоль?](#Что-выведется-в-консоль)
128 | * [Нужно сделать повторяемый таймер, который вызывается каждую минуту в бекграунде. Как это сделать?](#Нужно-сделать-повторяемый-таймер-который-вызывается-каждую-минуту-в-бекграунде-Как-это-сделать)
129 | * [Что произойдет после запуска приложения?](#Что-произойдет-после-запуска-приложения)
130 |
131 |
132 | # UIKit
133 |
134 | ## Чем отличаются bounds и frame?
135 |
136 | `frame` – это прямоугольник описываемый положением location(x, y) и размерами size (width, height) вьюхи относительно ее superview в которой она содержится.
137 | `bounds` – это прямоугольник описываемый положением location(x, y) и размерами size (width, height) вьюхи относительно ее собственной системы координат (0, 0).
138 |
139 |
140 |
141 | ## Когда bounds будет отлично от нуля?
142 |
143 | Рассмотрим на примере UIScrollView:
144 | Bounds будет отлично от нуля, когда contentOffset у скролла не равен (0;0)
145 |
146 | ## Как работает UITableView?
147 |
148 | Ячейки таблицы, которые больше не отображаются на экране, не выбрасываются из памяти. Их можно использовать повторно, указав идентификатор в процессе инициализации. Когда ячейка, отмеченная для повторного использования, пропадает с экрана, `UITableView` помещает ее в очередь для повторного использования в дальнейшем. Когда `dataSource` запрашивает у `UITableView` новую ячейку и указывает идентификатор, `UITableView` сначала проверяет очередь ячеек для повторного использования на предмет наличия необходимой. Если ячейка не была обнаружена, то создается новая, которая затем передается `dataSource`'у.
149 |
150 | ```objectivec
151 | UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
152 | ```
153 |
154 | ## Разница между points и pixels?
155 |
156 | -`Pixels` (px) - точки на экране.
157 | -`Points` (pt) - плотность точек на экране.
158 |
159 |
160 |
161 | ## Как поймать неприятный лаг? На что обращать внимание?
162 |
163 | Есть приложение с таблицей. В процессе скроллинга периодически наблюдаются легкие притормаживания. Тестировщики не выявили явной закономерности, но проблема регулярно встречается.
164 |
165 | Причиной торможения может быть:
166 | - Перегруженный `main thread`
167 | - Инстанциирующиеся ячейки. Если у вас таблица состоит больше, чем из одного вида ячеек, то при отсутствии в очереди нужной, она сначала создастся, это требует ресурсов. Особенно при разархивации из `nib`
168 | - Все касающееся прорисовки, подсчет высоты и переиспользуемые ресурсы
169 | - Тени и большое количество blur
170 | - Дробные значения фреймов у subviews
171 |
172 | ## Autolayout
173 |
174 | `Auto Layout` занимается динамическим вычислением позиции и размера всех view на основе constraints — правил заданных для того или иного view. Самый большой и очевидный плюс для разработчика в использовании `Auto Layout` в том, что исчезает необходимость в подгонке размеров приложения под определенные устройства. `Auto Layout` изменяет интерфейс в зависимости от внешних или внутренних изменений. Минус `Auto Layout` состоит в том, что вычисление конкретных значений сводится к задаче решения системы линейных уравнений, поэтому добавление каждого нового констрейнта ощутимо увеличивает сложность расчета конкретных значений.
175 |
176 | # SDK
177 |
178 | ## NSCoding, archiving
179 |
180 | `NSCoder` — это абстрактный класс, который преобразует поток данных. Используется для архивации и разархивации объектов. Протокол `` позволяет реализовать архивирование или разархивирование данных. Например, у нас есть обьект мы его можем сохранить, а при следующей загрузке приложения подгрузить обратно. Часто программе требуется хранить состояние объектов в файле для дальнейшего их полного либо частичного восстановления, а также работы с ними. Такой процесс называют сериализацией. Многие современные языки и фреймворки предоставляют для этого вспомогательные средства.
181 |
182 | Сохранить состояние объекта в Cocoa Framework можно двумя способами при помощи:
183 | * архивации (archivation)
184 | * сериализации (serialization)
185 |
186 | Каждый из них имеет свои области применения. Так, при помощи сериализации нельзя сохранить объект пользовательского класса. Рассмотрим подробнее оба способа. Протокол `` объявляет два метода, которые должен реализовать класс, так что экземпляры этого класса могут быть закодированы и декодированы. Эта возможность обеспечивает основу для архивирования (где объекты и другие структуры хранятся на диске) и распространения (где объекты копируются в разные адресные пространства).
187 |
188 | - `encodeWithCoder` : кодирует приемник с помощью данного архиватора. (обязательный)
189 | - `encodeWithCoder:(NSCoder *)encoder`
190 | - `initWithCoder` : возвращает объект инициализированный из данных в данном разархиваторе
191 | - `initWithCoder:(NSCoder *)decoder`
192 |
193 | ### Создание архивов
194 |
195 | Самый простой способ создать архив - использовать метод archiveRootObject:toFile: архиватора. Этот метод класса создает временный экземпляр архиватора и записывает объект в файл.
196 | ```objectivec
197 | MapView *myMapView;
198 | result = [NSKeyedArchiver archiveRootObject:myMapView toFile:@"/tmp/MapArchive"];
199 | ```
200 | ### Чтение архивов
201 |
202 | Для чтения архивов, также как и для записи (см. выше), можно использовать 2 метода. Первый - простой и пригодный для большинства случаев - с использованием метода класса:
203 | ```objectivec
204 | MapView *myMapView;
205 | myMapView = [NSKeyedUnarchiver unarchiveObjectWithFile:@"/tmp/MapArchive"];
206 | ```
207 | Второй метод предполагает создание экземпляра объекта NSKeyedUnarchiver.
208 |
209 | ## Как работают push-уведомления?
210 |
211 | `Push`- уведомление — это короткое сообщение, состоящее из токена девайса, полезной нагрузки (payload) и ещё некоторой информации. Полезная нагрузка — это актуальные данные, которые будут отправляться на девайс. Схема работы выглядит следующим образом:
212 | 1. Устройство запрашивает у `Apple Push Notification Service (APNS)` token своеобразный ключ, который можно считать «адресом»
213 | 2. Приложение отправляет token на сервер, который занимается отправкой push-уведомлений.
214 | 3. Когда произойдёт какое-либо событие для вашего приложения, сервер отправит push-уведомление в `APNS`.
215 | 4. `APNS` отправит push-уведомление на девайс пользователя.
216 |
217 | Для разработки push-уведомлений, надо учитывать следующие моменты:
218 | • Push-уведомления не работают в симуляторе, поэтому для тестирования нужен настоящий девайс.
219 | • Регистрация в iOS Developer Program. Для каждого приложения, в котором будет интегрирован механизм push-уведомлений, необходимо создать новый App ID и provisioning profile для сборки приложений, а также SSL-сертификат для отправки push-уведомлений. Эти действия выполняются на iOS Provisioning Portal.
220 | • Необходимо создать provisioning profile и SSL-сертификат.
221 | • Опционально сервер, подключенный к интернету. Push-уведомления обычно отправляются сервером, собственным, или сторонним (например, [Firebase](https://firebase.google.com/)). Также (в основном в целях отладки) push-уведомления можно отправлять прямо с компьютера, например, с помощью программы [Pusher](https://github.com/noodlewerk/NWPusher)
222 |
223 | Тонкие моменты при работе с push-уведомлениями:
224 | > 1. Нет гарантий, что push-уведомления будут доставлены, даже если APNS примет их.
225 | > 2. Как только ваш сервер сформировал push-уведомление, он безответно отправляет его в APNS. Нет способа узнать статус доставки уведомления конечному пользователю после отправки. Время доставки может варьироваться от нескольких секунд до получаса.
226 | > 3. APNS будет пытаться доставить последнее отправленное уведомление, когда девайс станет доступен для приёма. Но эти попытки ограничены по времени. После тайм-аута push-уведомление будет потеряно.
227 |
228 | ## Memory warning
229 |
230 | Этот метод вызывается, когда система обнаружила недостаточное количество памяти. Вы можете переопределить этот метод, чтобы освободить любую дополнительную память (например, кэш фотографий). После вызова этого метода приложение может быть закрыто системой.
231 | ```objectivec
232 | - (void)applicationDidReceiveMemoryWarning:(UIApplication *)application {
233 | /*
234 | Free up as much memory as possible by purging cached data objects that can be recreated (or reloaded from disk) later.
235 | */
236 | }
237 |
238 | - (void)didReceiveMemoryWarning {
239 | // Releases the view if it doesn't have a superview.
240 | [super didReceiveMemoryWarning];
241 | // Release any cached data, images, etc that aren't in use.
242 | }
243 | ```
244 |
245 | ## Жизненный цикл приложения
246 |
247 | `Not running` (не запущенное) — приложение не было запущено или его работа была прекращена.
248 | `Inactive` (неактивное) — приложение работает, но не принимает события (например, когда пользователь заблокировал телефон при запущенном приложении).
249 | `Active` (активное) — нормальное состояние приложения при его работе.
250 | `Background` (фоновое) — приложение больше не на дисплее, но оно все еще выполняет код.
251 | `Suspended` (приостановленное) — приложение занимает память, но не выполняет код.
252 |
253 |
254 | ## Жизненный цикл ViewController
255 |
256 | `load view` — создает вью, которой управляет контроллер. Вызывается при создании контроллера. Вы можете переопределить этот метод, чтобы создать свои вью вручную.
257 |
258 | `viewDidLoad` — вью создано и загружено в память, но нет bounds. Хорошее место для инициализации и настройки объектов, используемых во вью контроллере.
259 |
260 | `viewWillAppear` — вью будет добавлено в иерархию, определены bounds, но ориентация экрана не определена. Вызывается каждый раз, когда появляется вью.
261 |
262 | `viewWillLayoutSubviews` — вызывается каждый раз, когда frame изменился, например, при смене ориентации. Если вы не используете autoresizing masks или constraints, вы, вероятно, хотите обновить сабвью здесь.
263 |
264 | `viewDidLayoutSubviews` — вызывается уведомить контроллер, что его вью только что залэйаутил сабвью.
265 |
266 | `viewDidAppear` — вью добавлено в иерахию и появилось на экране. Хорошее место для выполнения задач, связанных с анимацией вью. Метод вызывается после того, как анимация загрузки вью закончена. Иногда хорошим кейсом в этом методе будет вытаскивать данные из кордаты и отображать на вью или запрашивать данные с сервера.
267 |
268 | `viewWillDissapear` — вью уходит с экрана. Вызывается как при закрытии вью контроллера, так и при переходе дальше по иерархии, например, при пуше нового контроллера в NavigationController
269 |
270 | `viewDidDissapear` — вью ушло с экрана. Вызывается как при закрытии вью контроллера, так и при переходе дальше по иерархии.
271 |
272 | # Паттерны
273 |
274 | ## Observer
275 |
276 | Паттерн, который помогает реагировать на изменения происходящие в объекте, – все подписанные на него объекты тут же узнают про изменение. Идея проста: объект который мы называем Subject – дает возможность другим объектам, которые реализуют интерфейс Observer, подписываться и отписываться от изменений происходящих в Subject. Когда изменение происходит – всем заинтерeсованным объектам высылается сообщение, что изменение произошло. В нашем случае – Subject – это издатель газеты, Observer это мы с вами – те кто подписывается на газету, ну и собственно изменение – это выход новой газеты, а оповещение – отправка газеты всем кто подписался.
277 |
278 | ### Способы реализации паттерна Observer
279 |
280 | `Notification` – механизм использования возможностей `NotificationCenter` самой операционной системы. Использование `NSNotificationCenter` позволяет объектам коммуницировать, даже не зная друг про друга. Это очень удобно использовать когда у вас в параллельном потоке пришел push-notification, или же обновилась база, и вы хотите дать об этом знать активному на даный момент View.
281 | Чтобы послать такое сообщение стоит использовать конструкцию типа:
282 | ```objectivec
283 | NSNotification *broadCastMessage = [NSNotification notificationWithName:@"broadcastMessage" object:self];
284 | ```
285 | Как видим мы создали объект типа `NSNotification` в котором мы указали имя нашего оповещения: "broadcastMessage", и собственно сообщили о нем через NotificationCenter.
286 | Чтобы подписаться на событие в объекте который заинтересован в изменении стоит использовать следующую конструкцию:
287 | ```objectivec
288 | NSNotificationCenter * notificationCenter = [NSNotificationCenter defaultCenter];
289 | [notificationCenter addObserver:self selector:@selector(update:) name:@"broadcastMessage" object:nil];
290 | ```
291 |
292 | Мы подписываемся на событие и вызывается метод, который задан в свойстве selector.
293 |
294 | ## Singleton
295 |
296 | Существует в системе в единственном экземпляре => не может быть повторно создан. Объект, к которому обращаются много объектов. Примеры синглтонов в системе:
297 |
298 | ```objectivec
299 | [NSUserDefaults standardUserDefaults];
300 | [UIApplication sharedApplication];
301 | [UIScreen mainScreen];
302 | [NSFileManager defaultManager];
303 | ```
304 |
305 | ### Минусы Singleton
306 |
307 | 1. Глобальное состояние. Про вред глобальных переменных вроде бы уже все знают, но тут та же самая проблема. Когда мы получаем доступ к экземпляру класса, мы не знаем текущее состояние этого класса, и кто и когда его менял, и это состояние может быть вовсе не таким, как ожидается. Иными словами, корректность работы с синглтоном зависит от порядка обращений к нему, что вызывает неявную зависимость подсистем друг от друга и, как следствие, серьезно усложняет разработку.
308 | 2. Зависимость обычного класса от синглтона не видна в публичном контракте класса. Так как обычно экземпляр синглтона не передается в параметрах метода, а получается напрямую, через GetInstance(), то для выявления зависимости класса от синглтона надо залезть в тело каждого метода — просто просмотреть публичный контракт объекта недостаточно.
309 | 3. Наличие синглтона понижает тестируемость приложения в целом и классов, которые используют синглтон, в частности. Во-первых, вместо синглтона нельзя подставить Mock-объект, а во-вторых, если синглтон имеет интерфейс для изменения своего состояния, то тесты начинают зависеть друг от друга. Говоря же проще — синглтон повышает связность, и все вышеперечисленное, в том или ином виде, есть следствие повышения связности.
310 |
311 | ## Lazy initialization
312 |
313 | Приём в программировании, когда некоторая ресурсоёмкая операция (создание объекта, вычисление значения) выполняется непосредственно перед тем, как будет использован её результат. Таким образом, инициализация выполняется «по требованию», а не заблаговременно. Аналогичная идея находит применение в самых разных областях: например, компиляция «на лету» и логистическая концепция «Точно в срок». Частный случай ленивой инициализации — создание объекта в момент обращения к нему — является одним из порождающих шаблонов проектирования.
314 |
315 | #### Достоинства
316 |
317 | - Инициализация выполняется только в тех случаях, когда она действительно необходима
318 | - Ускоряется начальная инициализация
319 |
320 | #### Недостатки
321 |
322 | - Невозможно явным образом задать порядок инициализации объектов
323 | - Возникает задержка при первом обращении к объекту
324 |
325 | #### Пример
326 | ```objectivec
327 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
328 | static NSString *CellIdentifier = @"CellIdentifier";
329 | cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
330 | if (cell == nil) {
331 | // ленивая загрузка
332 | cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
333 | reuseIdentifier:CellIdentifier];
334 | }
335 | cell.textLabel.text = someText;
336 | return cell;
337 | }
338 | ```
339 |
340 |
341 | ## Factory Method
342 |
343 | Также известен как виртуальный конструктор — порождающий шаблон проектирования, предоставляющий подклассам интерфейс для создания экземпляров некоторого класса. В момент создания наследники могут определить, какой класс создавать. Иными словами, Фабрика делегирует создание объектов наследникам родительского класса. Это позволяет использовать в коде программы не специфические классы, а манипулировать абстрактными объектами на более высоком уровне.
344 |
345 |
346 | ## Responder chain
347 |
348 | Это цепочка по которой проходит событие от отправителя к получателю, от First Responder, по иерархии контроллеров, до root view controller, window object и последнего - app object.
349 |
350 | - UIControl Actions (например, нажатие кнопки)
351 | - User events: (touches, shakes, motion, etc...)
352 | - System events: (low memory, rotation, etc...)
353 |
354 |
355 | # Архитектура
356 |
357 | ## MVC
358 |
359 | Концепция MVC позволяет разделить данные, представление и обработку действий пользователя на три отдельных компонента:
360 | - Модель (англ. `Model`). Модель предоставляет знания: данные и методы работы с этими данными, реагирует на запросы, изменяя своё состояние. Не содержит информации, как эти знания можно визуализировать.
361 | - Представление, вид (англ. `View`). Отвечает за отображение информации (визуализацию). Часто в качестве представления выступает форма (окно) с графическими элементами.
362 | - Контроллер (англ. `Controller`). Обеспечивает связь между пользователем и системой: контролирует ввод данных пользователем и использует модель и представление для реализации необходимой реакции.
363 |
364 | Важно отметить, что как представление, так и контроллер зависят от модели. Однако модель не зависит ни от представления, ни от контроллера. Тем самым достигается назначение такого разделения: оно позволяет строить модель независимо от визуального представления, а также создавать несколько различных представлений для одной модели.
365 |
366 | ### Активная модель
367 |
368 | `Активная модель` — модель оповещает представление о том, что в ней произошли изменения, а представления, которые заинтересованы в оповещении, подписываются на эти сообщения. Это позволяет сохранить независимость модели как от контроллера, так и от представления.
369 |
370 | ### Пассивная модель
371 |
372 | `Пассивная модель` — модель не имеет никаких способов воздействовать на представление или контроллер, и пользуется ими в качестве источника данных для отображения. Все изменения модели отслеживаются контроллером и он же отвечает за перерисовку представления, если это необходимо. Такая модель чаще используется в структурном программировании, так как в этом случае модель представляет просто структуру данных, без методов их обрабатывающих.
373 |
374 | ## MVVM
375 |
376 | Этот паттерн удобен в проектах, где используются такие фреймворки, как ReactiveCocoa i RxSwift, в которых есть концепция «связывания данных» — связывание данных с визуальными элементами в двустороннем порядке. В этом случае, использование паттерна MVC является очень неудобным, поскольку привязка данных к представлению (View) — это нарушение принципов MVC.
377 |
378 | View (ViewController) и Model имеют «посредника» — View Model. View Model — это независимое от UIKit представления View. View Model вызывает изменения в Model и самостоятельно обновляется с уже обновленным Model, и, так как связывание происходит через View, то View обновляется тоже.
379 |
380 | Недостатком является то, что «вместо 1000 строк в ViewController может выйти 1000 строк в ViewModel». Также одна из проблем использования фреймворков для «реактивного программирования» — достаточно просто все поломать и может пойти очень много времени на багфиксинг. Кому-то может показаться, что RxSwift, например, упрощает написание кода, но достаточно заглянуть в стек вызовов друга «rx-» метода, чтобы оценить это «упрощение». Можно сюда же добавить проблемы с документацией и постоянные проблемы с автокомплитом в xCode.
381 |
382 | ## MVP
383 |
384 | MVP-паттерн «эволюционировал» из MVC и состоит из таких трех компонентов:
385 |
386 | - Presenter (независимый посредник UIKit)
387 | - Passive View (UIView и/или UIViewController)
388 | - Model
389 |
390 | Этот паттерн определяет View как получающий UI-события от пользователя и тогда вызывает соответствующий Presenter, если это нужно. Presenter же отвечает за обновление View с новыми данными, полученными из модели.
391 |
392 | #### Достоинства
393 | - лучшее разделение кода
394 | - хорошо тестируется
395 |
396 | #### Недостатки
397 | - сравнительно с MVC имеет значительно больше кода
398 | - разработка и поддержка занимают больше времени
399 |
400 | ## Viper
401 |
402 | От вышеперечисленных паттернов отличается тем, что не относится к категории MVC. Вместо привычных 3-х слоев он предлагает 5:
403 | 1. View
404 | 2. Interactor
405 | 3. Presenter
406 | 4. Entity
407 | 5. Router
408 |
409 | View: отвечает за отображение данных на экране и оповещает Presenter о действиях пользователя. Как правило слоем View в данной модели является ViewController. Пассивен, сам никогда не запрашивает данные, только получает их от презентера. Не содержит в себе логики отображения: принимает от presenter готовые к отображению данные, например, готовые строки текста, и размещает их на себе. События пользователя передает в presenter, который их обрабатывает.
410 |
411 | Interactor: содержит бизнес-логику, связанную с получением данных (Entities).
412 |
413 | Presenter: получает от View информацию о действиях пользователя и преображает ее в запросы к Router’у, Interactor’у, а также получает данные от Interactor’a, подготавливает их и отправляет View для отображения
414 |
415 | Entity: простые объекты данных, по сути модель хранящая информацию и ничего более, они не являются слоем доступа к данным, так как это ответственность Interaptor.
416 |
417 | Router: несет ответственность за переходы между VIPER-модулями.
418 |
419 | Даже при таком поверхностном осмотре очевидно, что лучшее разделение обязанностей получается за счет большого количества классов с небольшим количеством обязанностей.
420 |
421 | # ООП
422 |
423 | ## Киты ООП
424 |
425 | ### __Абстракция__
426 | – это придание объекту характеристик, отличающих от всех других объектов, при этом игнорируя ее некоторые детали. Имея дело с составным объектом, вы имеете дело с абстракцией. Если вы рассматриваете объект как «дом», а не как комбинацию стекла, древесины и гвоздей, вы прибегаете к абстракции. Если вы рассматриваете множество домов как «город», вы прибегаете к другой абстракции.
427 |
428 | ### __Инкапсуляция__
429 | – скрытие методов и переменных от других методов или переменных или других частей программы. Целособразно:
430 |
431 | Инкапсуляция позволяет вам знать о существовании двери, о том, открыта она или заперта, но при этом вы не можете узнать, из чего она сделана (из дерева, стекловолокна, стали или другого материала), и уж никак не сможете рассмотреть отдельные волокна древесины.
432 |
433 | ### __Наследование__
434 | – процесс, посредством которого один объект может приобретать свойства другого и добавлять к ним черты, характерные только для него. Польза наследования в том, что оно дополняет идею абстракции. Наследование упрощает программирование, позволяя создать универсальные методы для выполнения всего, что основано на общих свойствах дверей, и затем написать специфические методы для выполнения специфических операций над конкретными типами дверей. Некоторые операции, такие как `Open()` или `Close()`, будут универсальными для всех дверей: внутренних, входных, стеклянных, стальных — каких угодно.
435 |
436 | ```objectivec
437 | @interface Unicycle : NSObject {
438 | Pedal *pedal;
439 | Tire *tire;
440 | }
441 | @end
442 | ```
443 |
444 | ### __Полиморфизм__
445 | – возможность объектов с одинаковой спецификацией иметь различную реализацию (использование одного имени для решения двух или более схожих, но технически разных задач). Если функция описывает разные реализации (возможно, с различным поведением) для ограниченного набора явно заданных типов и их комбинаций, это называется ситуативным полиморфизмом (ad hoc polymorphism). Ситуативный полиморфизм поддерживается во многих языках посредством перегрузки функций и методов.
446 | Если же код написан отвлеченно от конкретного типа данных и потому может свободно использоваться с любыми новыми типами, имеет место параметрический полиморфизм. Некоторые языки совмещают различные формы полиморфизма, порой сложным образом, что формирует самобытную идеологию в них и влияет на применяемые методологии декомпозиции задач. Например, в Smalltalk любой класс способен принять сообщения любого типа, и либо обработать его самостоятельно (в том числе посредством интроспекции), либо ретранслировать другому классу — таким образом, несмотря на широкое использование перегрузки функций, формально любая операция является неограниченно полиморфной и может применяться к данным любого типа.
447 |
448 | ## Плюсы и минусы ООП
449 |
450 | __Общие положения__
451 |
452 | _Преимущества_
453 |
454 | * Классы позволяют проводить конструирование из полезных компонент, обладающих простыми инструментами, что дает возможность абстрагироваться от деталей реализации.
455 |
456 | _Недостатки_
457 |
458 | * ООП порождает огромные иерархии классов, что приводит к тому, что функциональность расползается или, как говорят, размывается по базовым и производным членам класса, и отследить логику работы того или иного метода становится сложно.
459 |
460 | __Полиморфизм__
461 |
462 | _Преимущества_
463 |
464 | * Можно создавать новые классы с помощью протокола, «ведущие себя» аналогично родственным, что, в свою очередь, позволяет достигнуть расширяемости и модифицируемости, что помогает снижать сложность программ, разрешая использование того же интерфейса для задания единого класса действий. "Один интерфейс, множество методов"
465 | * Возможность создавать переменные и методы с одинаковым именем, но ведущие себя по-разному в зависимости от контекста (локальные переменные и перекрытие методов)
466 | * Обработка разнородных структур данных. Программы могут работать, не утруждая себя изучением вида объектов. Новые виды могут быть добавлены в любой момент.
467 | ```objectivec
468 | for (id object in array) {
469 | NSLog(@"%@", object);
470 | }
471 | ```
472 | * Реализация родовых компонент. Алгоритмы можно обобщать до такой степени, что они уже смогут работать более, чем с одним видом объектов.
473 | Доведение полуфабрикатов. Компоненты нет надобности подстраивать под определенное приложение. Их можно сохранять в библиотеке в виде полуфабрикатов (semifinished products) и расширять по мере необходимости до различных законченных продуктов.
474 | Расширение фреймворка. Независимые от приложения части предметной области могут быть реализованы в виде фреймворка и в дальнейшем расширены за счет добавления частей, специфичных для конкретного приложения.
475 |
476 | _Недостатки_
477 |
478 | * На скорости выполнения программ может неблагоприятно сказаться реализация полиморфизма, которая основана на механизмах позднего связывания вызова метода с конкретной его реализацией в одном из производных классов.
479 | * Многоразовое использование требует от программиста познакомиться с большими библиотеками классов. А это может оказаться сложнее, чем даже изучение нового языка программирования. Библиотека классов фактически представляет собой виртуальный язык, который может включать в себя сотни типов и тысячи операций.
480 | * В некоторых языках все данные являются объектами, в том числе и элементарные типы, а это не может не приводить к дополнительным расходам памяти и процессорного времени.
481 | * Изменение поведения во время выполнения. На этапе выполнения один объект может быть заменен другим. Это может привести к изменению алгоритма, в котором используется данный объект.
482 |
483 | __Инкапсуляция__
484 |
485 | _Преимущества_
486 |
487 | * Сокрытие данных от несанкционированного доступа
488 | * Инкапсуляция повышает надежность работы программного кода, поскольку гарантирует, что определенные данные не могут быть изменены за пределами содержащего их класса.
489 |
490 | _Недостатки_
491 |
492 | * Функции представляют собой черные ящики, которые трансформируют ввод в вывод. Если я понимаю ввод и вывод, то я понимаю функцию. Это не означает, что я могу написать эту функцию.
493 | * В то время как состояние в языках программирования является нежелательным, реальный мир богат на состояния. Я очень интересуюсь состоянием моего банковского счета. И когда я вкладываю или снимаю с него деньги, я ожидаю, что его состояние будет корректно обновлено. Выбранный ООЯП подход “спрятать состояние от программиста” является наихудшим возможным выбором. Вместо показа состояния и поиска путей для минимизации неудобств от него, они прячут его поглубже.
494 | * Очень трудно изучать классы, не имея возможности их «пощупать». Только с приобретением мало-мальского опыта можно уверенно себя почувствовать при работе с использованием ООП. Поэтому проектирование классов — задача куда более сложная, чем их использование. Проектирование класса, как и проектирование языка, требует большого опыта. Это итеративный процесс, где приходится учиться на своих же ошибках.
495 |
496 | __Наследование__
497 |
498 | _Преимущества_
499 |
500 | * Когда вас почти устраивает какой-то класс, вы можете создать потомка и переопределить какую-то часть его функциональности.
501 | * Лаконичность абстракции данных, созданной с помощью наследования, является преимуществом. Используя наследование, не обязательно писать весь код для доступа к функциям базового класса. По этой причине реализации с использованием наследования (как это было в нашем случае) значительно меньше по объему, если сравнить их с композицией.
502 |
503 | _Недостатки_
504 |
505 | * Унаследовавшись от одного предка, класс уже не может наследоваться от других. Изменение предка так же становится опасным.
506 | * О степени понятности кода судить трудно. Чтобы точно знать, какие операции разрешены для новой структуры, программист должен рассмотреть объявление ис-ходной структуры. Трудность состоит в следующем: чтобы понять класс, сконструированный с помощью наследования, программист должен постоянно переключаться «взад-вперед» между двумя (или более) описаниями классов. Она известна как проблема «вверх-вниз». В сложных иерархиях классов поля и методы обычно наследуются с разных уровней. И не всегда легко определить, какие поля и методы фактически относятся к данному классу.
507 | * Наследование – уничтожение инкапсуляции. Любой класс всегда неявно объявляет свой интерфейс — то, что доступно при использовании класса извне. Если у нас есть класс Ключ и у него публичный метод Открыть, который вызывает приватные методы Вставить, Повернуть и Вынуть, то интерфейс класса Ключ состоит из метода Открыть. Когда мы унаследуем какой-то класс от класса Ключ, он унаследует этот интерфейс. Кроме этого интерфейса, у класса есть также реализация — методы Вставить, Повернуть, Вынуть и их вызов в методе Открыть. Наследники Ключа наследуют вместе с интерфейсом и реализацию. И вот здесь таятся проблемы.
508 |
509 | ## Что такое SOLID?
510 |
511 | `SOLID` (сокр. от англ. Single responsibility, Open-closed, Liskov substitution, Interface segregation и Dependency inversion) - акроним, введённый Майклом Фэзерсом для первых пяти принципов, названных Робертом Мартином в начале 2000-х, которые означали пять основных принципов ООП и проектирования.
512 |
513 | #### Принцип единственной ответственности
514 | обозначает, что каждый объект должен иметь одну ответственность и эта ответственность должна быть полностью инкапсулирована в класс. Все его поведения должны быть направлены исключительно на обеспечение этой ответственности. Следующие приёмы позволяют соблюдать принцип единственной ответственности: выделение класса, фасад, DAO.
515 |
516 | #### Принцип открытости / закрытости
517 | означает, что программные сущности должны быть:
518 | - открыты для расширения: поведение сущности может быть расширено, путём создания новых типов сущностей
519 | - закрыты для изменения: в результате расширения поведения сущности, не должны вносится изменения в код, которые эти сущности использует
520 |
521 | #### Принцип подстановки Барбары Лисков
522 | даёт определение понятия замещения — если S является подтипом T, тогда объекты типа T в программе могут быть замещены объектами типа S без каких-либо изменений желательных свойств этой программы (например, корректность). Более простыми словами можно сказать, что поведение наследуемых классов не должно противоречить поведению, заданному базовым классом, то есть поведение наследуемых классов должно быть ожидаемым для кода, использующего переменную базового типа.
523 |
524 | #### Принцип разделения интерфейса Роберт Мартин
525 | определил так: «Клиенты не должны зависеть от методов, которые они не используют». Принцип разделения интерфейсов говорит о том, что слишком «толстые» интерфейсы необходимо разделять на более маленькие и специфические, чтобы клиенты маленьких интерфейсов знали только о методах, которые необходимы им в работе. В итоге, при изменении метода интерфейса не должны меняться клиенты, которые этот метод не используют.
526 |
527 | #### Принцип инверсии зависимостей
528 | — принцип, используемый для уменьшения зацепления в компьютерных программах.
529 | Модули верхних уровней не должны зависеть от модулей нижних уровней. Оба типа модулей должны зависеть от абстракций.
530 | Абстракции не должны зависеть от деталей. Детали должны зависеть от абстракций.
531 |
532 | ## Что такое нарушение инкапсуляции?
533 |
534 | Наружу (т.е. public) торчат какие-то данные, которые можно изменить, и объект уходит в противоречивое состояние.
535 |
536 | ## Понятия ОО-программирования в Objective-C
537 |
538 | `@interface` Начинает объявление класса или категории (категория – расширение класса дополнительными методами без наследования).
539 | `@implementation` Начинает определение класса или категории.
540 | `@protocol` Начинает объявление протокола (аналог класса С++, состоящего из чисто виртуальных функций).
541 | `@end` Завершает объявление\определение любого класса, категории или протокола.
542 | `@private` Ограничивает область видимости инвариантов класса методами класса (аналогично С++).
543 | `@protected` Стоит по умолчанию. Ограничивает область видимости инвариантов класса методами класса и методами производных классов (аналогично С++).
544 | `@public` Удаляет ограничения на облать видимости (аналогично С++).
545 | `@try` Определяет блок с возможной генерацией исключений (аналогично С++).
546 | `@throw` Генерирует объект-исключение (аналогично С++).
547 | `@catch` () Обрабатывает исключение, сгенерированное в предшествующем блоке `@try` (аналогично С++).
548 | `@finally` Определяет блок после блока @try, в который предается управление независимо от того, было или нет сгенерировано исключение.
549 | `@class` Сокращенная форма объявления класса (только имя (аналогично С++)).
550 | `@selector(method_name)` Возвращает скомпилированный селектор для имени метода method_name.
551 | `@protocol(protocol_name)` Возвращает экземпляр класса-протокола с именем protocol_name.
552 | `@encode(type_spec)` Инициализирует строку символов, которая будет использована для шифрования данных типа type_spec.
553 | `@synchronized()` Определяет блок кода, выполняющегося только одной нитью в любой определенный момент времени.
554 |
555 | # Управление памятью
556 |
557 | ### Garbage Collector
558 |
559 | Это особенный режим управления памятью, основанный на периодическом запуске сборщика мусора. Мы выделяем память, но не освобождаем ее. За нас память освобождает сборщик мусора. Но он имеет ряд огромных недостатков:
560 | - Его должны поддерживать все без исключения используемые библиотеки. Скажем, если ARC позволяет использовать не-ARC подход, то с GС такое не пройдет, либо программа и все ее библиотеки полностью поддерживают этот метод управления памятью, либо программа просто не будет скомпилирована
561 | - Сборка мусора - это достаточно ресурсоемкая задача, она требует как дополнительной памяти, так и достаточно много процессорного времени. И каждый раз, когда программа будет вызывать сборщик мусора, выполнение программы в это время будет сопровождаться достаточно заметным подтормаживанием
562 |
563 | ## ARC
564 |
565 | Автоматический подсчет ссылок является компиляторной функцией, которая обеспечивает автоматическое управление памятью в Objective-C объектах. Вместо того, чтобы думать о со-хранении и освобождении объектов, ARC позволяет сосредоточиться на непосредственном коде Вашего приложения. ARC работает путем добавления кода во время компиляции, чтобы время жизни объекта было ровно столько, сколько необходимо, но не более того. Концептуально, это то же управление памятью, что и ручной подсчет ссылок (описанное в практическом управлении памятью) путем добавления соответствующего кода управления памятью, за вас. ARC поддерживается начиная с Xcode 4.2 для Mac OS X v10.6 и v10.7 (64-bit applications), а также iOS 4 и iOS 5. Слабые (`weak`) ссылки не поддерживаются в Mac OS X v10.6 и iOS 4 и более ранних.
566 | Существует несколько ограничений на использование механизма ARC.
567 | * Нельзя использовать свойство, имя которого начинается со слова `new`. Например, не допускается объявление
568 | ```objectivec
569 | @property NSString *newString;
570 | ```
571 | * Нельзя использовать свойство только для чтения без атрибутов управления памятью. Если вы не используете механизм ARC, то можете использовать объявление
572 | ```objectivec
573 | @property (readonly) NSString *title;
574 | ```
575 | Но если вы используете механизм ARC, то должны указать, кто управляет памятью, так что достаточно просто вставить ключевое слово unsafe_unretained, потому что по умолчанию используется атрибут `assign`.
576 |
577 |
578 | ## Освобождение памяти в MRC
579 |
580 | Способ 1 - полностью ручное освобождение памяти (`[str release];`). Вызов данной функции уменьшает счетчик ссылок у объекта на 1. Если после вызова, количество ссылок становится 0, то объект деаллоцируется из памяти. Если указатель хотите использовать далее, то рекомендуется после этого выполнить следующую конструкцию:
581 | `str = nil;`
582 |
583 | Способ 2 - `[str autorelease];` - а вот этот способ требует более детального рассмотрения. Для каждого потока формируется определенный пул, куда записываются методы, память которых вы не хотите освобождать моментально. То есть после выполнения этого оператора, объект какое то время будет доступен.
584 |
585 | А теперь как узнать, какое это время? Тут есть два варианта:
586 | 1) пока не выполнится команда `[pool drain]` (в версиях XCode < 4), или пока не выйдете из блока `@autorelease pool { ... }`;
587 | 2) Либо на следующем витке цикла EventMessage. То есть каждый виток цикла сообщений ведет к просмотру объектов в пуле, обозначенных для удаления методом autorelease.
588 |
589 | К сожалению, ко второму случаю, аналогию в чистом языке C++ со стандартной библиотекой я привести не могу, так как такого пула нет, но скорее всего есть какие-либо сторонние библиотеки, которые реализуют подобный механизм.
590 | А вот аналог первого варианта в C++ всем известен: `delete str;`
591 | Так же при создании объекта, можно сделать его изначально как autorelease.
592 | Например можно создать объект следующей строкой:
593 | `NSMutableString *str1 = [[[NSMutableStirng alloc] init] autorelease];`
594 | Такой способ выделит память под новый объект, инициализирует его, а затем изначально сообщит в пул, что удаление объекта кладется на плечи autorelease пула, после чего передаст указатель на объект переменной str1.
595 | В итоге, объект, находящийся по адрессу, записанному в str1 автоматический уничтожится по условию освобождения пула.
596 | Кстати, после такой записи, если вызвать `[str1 release];` - то объект сразу же будет уничтожен, но при попытке освободить пул, получим исключение, и последующий вылет из программы с ошибкой удаления несуществующего объекта.
597 | Так же есть такой стандартизированный способ создания авторелизнутых объектов классов как применение Convenience конструкторов.
598 | Еще хотелось бы порекомендовать, по возможности всегда использовать release вместо autorelease при программировании под iOS. Конечно, проще было бы создать объект изначально авторелизнутым и забыть про удаление объекта, эдакий почти сборщик мусора). Но не забывайте, что если пул очищается очень редко, то при программировании для мобильных устройств, где количество памяти ограничено, можно столкнутся с проблемой нехватки памяти еще до то того, как пул будет очищен.
599 | Еще один момент связанный с autorelease pool - если в основном потоке, каждый новый виток циклов сообщений (Event Message) очищает пул, то в потоках реализация периодической очистки пула ложиться на плечи программиста. Поэтому не забывайте иногда делать [pool drain];.
600 | P.s я так понимаю, что в версии XCode начиная с 4.2 [pool drain] делать уже не обязательно, так как там пул освобождается автоматический при выходе операторов за скобки
601 | `
602 | @autorelease pool {
603 | текст программы
604 | }
605 | `
606 | # Язык
607 |
608 | ## Различия isKindOfClass и isMemberOfClass
609 |
610 | `isKindOfClass`: возвращает логическое значение, указывающее, является ли приемник экземпляром заданного класса или экземпляром любого класса, который наследует от этого класса.
611 | `isMemberOfClass`: возвращает логическое значение, указывающее, является ли приемник экземпляром заданного класса.
612 |
613 | ## Когда лучше использовать категорию, а когда наследование?
614 |
615 | В отличие от наследования, категории не могут добавлять новые переменные в класс. Однако, вы можете переопределять существующие методы в классе, но должны быть очень осторожны. Запомните, что все изменения сделанные в классе через категории повлияют на экземпляры данного объекта в программе.
616 |
617 | ## Из чего состоит NSError?
618 |
619 | Существует три части объекта `NSError`:
620 | 1. Domain - это строка, которая идентифицирует категорию ошибок, из которых исходит эта ошибка
621 | 2. Error code - это числовой идентификатор ошибки
622 | 3. UserInfo - это описание ошибки
623 |
624 | ## KVC
625 |
626 | `KVC (Key-Value Coding)` представляет собой механизм для доступа к свойству объекта косвенно, с помощью строк для идентификации свойств, а не через вызов аксессора или доступ к ним непосредственно через переменных экземпляра. Часто используется для фильтрации в массивах (NSPredicate).
627 |
628 | ## Forward Invocation
629 | Это механизм обработки любого сообщения. То есть если мы посылаем сообщение некоторому объекту, но ни у кого из его иерархии не найдется селектора для обработки, то вызовется метод
630 |
631 | ```objectivec
632 | - (void)forwardInvocation:(NSInvocation *)anInvocation;
633 | ```
634 |
635 | ## Fast enumeration
636 |
637 | Это итерация по обьектам любого класса, который реализует протокол `NSFastEnumeration`, в том числе NSArray, NSSet и NSDictionary. Реализация протокола состоит из одного метода:
638 | ```objectivec
639 | -(NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(id *)stackbuf count:(NSUInteger)len;
640 | ```
641 |
642 | ## Чем объект Objective-C отличается от структуры С?
643 |
644 | Структура – специальный тип данных языка C, который содержит в себе другие типы данных в одном блоке и группрует их под одним именем. Объекты в Objective-C представляют собой структуры в которых имеется ссылка на объект класса.
645 |
646 | ## Что такое runLoop, когда он используется?
647 |
648 | Циклы выполнения (run loop) - цикл обработки событий, который используется для планирования работы и координации получения входящих событий. Объект NSRunLoop также обрабатывает события NSTimer (он не будет работать в потоке, в котором нет NSRunloop)
649 |
650 | ## nil, Nil, NULL, NSNull
651 |
652 | ` #define nil (id)0` - это указатель на нулевой объект.
653 | ` #define NULL ((void *)0)` - используется для указателей (тоже самое что nil).
654 | ` #define Nil (Class)0` - нулевой указатель типа Class.
655 | `NSNull` — это своего рода обёртка над NULL и nil, позволяющая хранить их в объектах-коллекциях Objective-C.
656 |
657 | ## Протоколы
658 |
659 | Цели для которых используются протоколы:
660 | - Ожидание, что класс поддерживающий протокол выполнит описанные в протоколе функции
661 | - Поддержка протокола на уровне объекта, не раскрывая методы и реализацию самого класса (в противоположность наследованию)
662 | - Ввиду отсутствия множественного наследования - объединить общие черты нескольких классов
663 |
664 | #### Формальные протоколы
665 |
666 | Объявление формального протокола гарантирует, что все методы объявленные протоколом будут реализованы классом.
667 |
668 | #### Неформальные протоколы
669 |
670 | Добавление категории к классу NSObject называется созданием неформального протокола. При работе с неформальными протоколами мы реализуем только те методы, которые хотим. Узнать поддержевает ли класс какой-либо метод можно с помощью селекторов:
671 | ```objectivec
672 | First *f = [[First alloc] init];
673 | if ([f respondsToSelector:@selector(setName:)]) {
674 | NSLog (@"Метод поддерживается");
675 | }
676 | ```
677 |
678 |
679 | ## Что такое `@dynamic`?
680 |
681 | `@dynamic` используется для делегирования ответственности за реализацию аксессеров.
682 | `@dynamic` для свойств означает, что сеттеры и геттеры будут созданы вручную и/или в runtime.
683 |
684 | ## Тип id
685 |
686 | Переменная типа id фактически является указателем на произвольный объект. Для обозначения нулевого указателя на объект используется константа nil. При этом вместо id можно использовать и более привычное обозначение с явным указанием класса. В частности последнее позволяет компилятору осуществлять некоторую проверку поддержки сообщения объектами — если компилятор из типа переменной не может сделать вывод о поддержке объектом данного сообщения, то он выдаст предупреждение, а не ошибку.
687 |
688 | ## defer
689 |
690 | Использование блока defer внутри метода означает, что отложенная работа будет выполнена перед выходом из метода. Например:
691 |
692 | ```objectivec
693 | override func viewDidLoad() {
694 | super.viewDidLoad()
695 |
696 | print("Шаг 1")
697 | myFunc()
698 | print("Шаг 5")
699 | }
700 |
701 | func myFunc() {
702 | print("Шаг 2")
703 | defer { print("Шаг 3") }
704 | print("Шаг 4")
705 | }
706 | ```
707 |
708 | Этот код напечатает "Шаг 1", "Шаг 2", "Шаг 4", "Шаг 3", "Шаг 5". Шаги 3 и 4 поменялись местами из-за того, что "Шаг 3" является отложенным до тех пор, пока не закончится выполнение метода myFunc(), то есть пока не выйдет за пределы видимости.
709 |
710 | Но есть одна небольшая загвоздка - ваши вызовы defer не должны пробовать покинуть текущую зону видимости при использовании return или, выкидывая ошибку. Все остальное что делается с defer, все к лучшему!
711 |
712 |
713 | ## Как работает механизм сообщений?
714 |
715 | Компилятор переводит каждую посылку сообщения, т.е. конструкцию вида `[object msg]` в вызов функции `objc_msgSend`.
716 |
717 | Эта функция в качестве своего первого параметра принимает указатель на объект-получатель сообщения, в качестве второго параметра выступает селектор, служащий для идентификации посылаемого сообщения. Если в сообщении присутствуют аргументы, то они также передаются в функции objc_msgSend как третий, четвертый и т.д. параметры.
718 |
719 | Каждый объект Objective-C содержит в себе атрибут isa - указатель на class object для данного объекта. class object автоматически создается компилятором и существует как один экземпляр, на который через isa ссылаются все экземпляры данного класса.
720 |
721 | Каждый `class object` обязательно содержит в себе указатель на class object для родительского класса (superclass) и dispatch table. `Dispatch Table `представляет из себя словарь, сопоставляющий селекторам сообщений фактические адреса реализующих их методов (функций).
722 |
723 | Функция objc_msgSend ищет метод с данным селектором в dispatch table для данного объекта. Если его там нет, то поиск продолжается в dispatch table для его родительского класса и т.д.
724 |
725 |
726 | ## Приватные методы в Objective-C
727 |
728 | Objective-С нет приватных(защищенных методов). Нужно использовать расширение. Для имитации private методов с помощью расширения, нужно в .m файле, перед @implementation добавить безымянную категорию.
729 |
730 | Для класса NetworkManager ее определение будет выглядеть как:
731 | ```objectivec
732 | @interface NetworkManager ()
733 | ...
734 | @end
735 | ```
736 |
737 | Стоит обратить особое внимание на пустые скобки — они показывают, что мы определяем именно безымянную категорию. После этого, мы можем добавлять в категорию методы, которые будут для нас считаться private. За счет того, что категория безымянная, имплементация данных методов может находиться рядом с имплементацией основных методов в разделе @implementation .. @end и нет необходимости создавать отдельные разделы для имплементации категорий. А за счет того, что она находится в .m файле, которые никто не подключает через #import, видимость методов для автодополнения ограничена текущим файлом.
738 |
739 | Конечно, послать объекту это сообщение извне все равно возможно, но от случайного вызова вы точно застрахованы.
740 |
741 |
742 | ## Можно ли добавить ivar в категорию?
743 |
744 | Директива `@interface` для категорий не может добавлять переменных экземпляра. Однако, она может определять, что категория поддерживает дополнительные протоколы.
745 |
746 |
747 | ## Что такое указатель isa? Для чего он нужен?
748 |
749 | Каждый объект Objective-C содержит в себе атрибут `isa` - указатель на class object для данного объекта. `class object` автоматически создается компилятором и существует как один экземпляр, на который через isa ссылаются все экземпляры данного класса.
750 |
751 | ```objectivec
752 | typedef struct objc_object {
753 | Class isa;
754 | } *id;
755 | ```
756 |
757 | ## В чем отличие void* от id?
758 |
759 | Отличие в том, что `id` указатель на objective - c объекты, а `void*` указатель на неопределенный тип, или просто область в памяти (в которой может хранится все что угодно).
760 |
761 | ## KVO
762 |
763 | Еще одна реализация паттерна наблюдатель. В этом случае наблюдатель следит за конкретным свойством объекта. Когда значение этого свойства меняется, наблюдателю приходит уведомление и он соответствующим образом реагируют. По сравнению со многими другими языками реализация KVO в Objective-C радуют довольно простым синтаксисом. Так в коде наблюдателя достаточно написать:
764 |
765 | ```objectivec
766 | [company_a addObserver:self forKeyPath:@"people" options:NSKeyValueObservingOptionNew context:nil];
767 | ```
768 |
769 | И каждый раз, когда в company_a будет изменяться значение переменной people наблюдатель будет уведомляться с помощью вызова метода.
770 | ```objectivec
771 | observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
772 | ```
773 | Надо лишь реализовать код, который будет реагировать на уведомление
774 |
775 | ### Плюсы
776 |
777 | - Минимализм кода (достаточно написать всего лишь несколько строчек, чтобы полностью реализовать паттерн наблюдатель)
778 | - Возможность слежения за любыми свойствами любых классов как написанными нами, так и чужими. Фактически внешние переменные всегда оформляются через свойства, что позволяет с легкостью следить любыми изменениями
779 |
780 | ### Недостатки
781 |
782 | - Заметное падение производительности при обильном использовании KVO. Не стоит писать код, где ваши объекты общаются в основном через KVO. Рассматривайте KVO как вспомогательно средство для работы с чужим кодом, а не как основной инструмент
783 | - Необходимость очень аккуратно писать код при использовании KVO. Так как строковые идентификаторов не проверяются компилятором на валидность, то это может привести к ошибкам при переименовании переменных. Также, KVO очень чувствительно к порядку добавления / удаления наблюдателей. Так, если наблюдатель пытается отписаться от наблюдаемого, на который наблюдатель в данный момент не подписан, то происходит крэш. Если же, наоброт, наблюдатель не отпишется до того, как наблюдаемый будет уничтожен, то произойдет утечка памяти
784 |
785 |
786 | ## `Atomic` vs `nonatomic`. Переопределение сеттера в MRC?
787 |
788 | Cинхронизировать чтение/запись между потоками или нет.
789 | `Atomic` – thread safe. Тут все сложнее и неоднозначнее, есть ряд способов как сделать threadsafe аксессоры к пропертям. Самый простой способ это сделать – добавить конструкцию @synchronized:
790 | ```objectivec
791 | - (NSString *)foo {
792 | @synchronized(self) {
793 | return foo;
794 | }
795 | }
796 |
797 | - (void)setFoo:(NSString)newFoo {
798 | @synchronized(self) {
799 | if (foo != newFoo) {
800 | [foo release];
801 | foo = [newFoo retain];
802 | }
803 | }
804 | }
805 | ```
806 | Таким образом используя `@synchronized` мы лочим по ключу self доступ к foo, однако у такого метода есть очевидный недостаток, если в классе будет две переменные (или 100500) к которым нужен одновременный доступ с разных потоков, то они будут лочиться и друг относительно друга, т.к self для них один и тот же, в таких случаях нужно использовать другие методы лока, как NSLock, NSRecursiveLock,...
807 |
808 |
809 | ## Чем отличается include от import?
810 |
811 | `import` защищен от многократного включения кода
812 |
813 |
814 | ## Что такое селектор (selector)? Как его вызвать?
815 |
816 | Селектор - это имя метода закодированное специальным образом, используемым языком для быстрого поиска. Указание компилятору на селектор происходит при помощи директивы `@selector(метод)`
817 |
818 | ```objectivec
819 | `First* f = [[First alloc] init];
820 | if([f respondsToSelector:@selector(setName:)])
821 | NSLog (@"Метод поддерживается");`
822 | ```
823 |
824 | В этом примере создается экземпляр класса First - f (наследник NSObject), после с помощью метода respondsToSelector проверяем может ли класс ответить на метод setName
825 |
826 | ## Что такое замыкания и где их можно использовать?
827 |
828 | Замыкания представляют собой самодостаточные фрагменты кода, которые могут быть переданы функции в качестве аргумента или использованы в программе.
829 | Замыкания в Swift похожи на блоки в C и Objective-C и на лямбды в других языках программирования.
830 | Это почти то же самое, что и функции, но замыкания не обязательно должны быть именованными.
831 | Нет необходимости объявлять тип каждого параметра, но если вы это делаете, то вам не нужно указывать тип возвращаемого значения.
832 |
833 | ## Что такое убегающие и неубегающие замыкания (escaping/nonescaping closures)?
834 |
835 | @nonescaping (стандартные) замыкания:
836 |
837 | Когда замыкание передается в аргументах функции и используется до того, как выполнится тело функции и управление вернется обратно.
838 | Когда функция завершается, переданное замыкание выходит из области видимости и больше не существует в памяти.
839 |
840 | @escaping (убегающие) замыкания:
841 |
842 | Когда замыкание передается в аргументах функции и используется после того, как выполнится тело функции и управление вернется обратно.
843 | Когда функция завершается, переданное замыкание продолжает существовать в области видимости и находится в памяти, пока замыкание не будет выполнено.
844 |
845 | # Общие вопросы
846 |
847 | ## Архитектура REST
848 |
849 | `REST` (Representational state transfer) – это стиль архитектуры программного обеспечения для распределенных систем, таких как World Wide Web, который, как правило, используется для построения веб-служб. Термин REST был введен в 2000 году Роем Филдингом, одним из авторов HTTP-протокола. Системы, поддерживающие REST, называются RESTful-системами. Каждая единица информации однозначно определяется глобальным идентификатором, таким как URL. Каждый URL в свою очередь имеет строго заданный формат. Вот как это будет выглядеть на примере:
850 | GET /book/ — получить список всех книг
851 | GET /book/3/ — получить книгу номер 3
852 | PUT /book/ — добавить книгу (данные в теле запроса)
853 | POST /book/3 — изменить книгу (данные в теле запроса)
854 | DELETE /book/3 — удалить книгу
855 |
856 | Как необходимые условия для построения распределенных REST-приложений Филдинг перечислил следующие:
857 | - Клиент-серверная архитектура.
858 | - Сервер не обязан сохранять информацию о состоянии клиента.
859 | - В каждом запросе клиента должно явно содержаться указание о возможности кэширования ответа и получения ответа из существующего кэша.
860 | - Клиент может взаимодействовать не напрямую с сервером, а с произвольным количеством промежуточных узлов. При этом клиент может не знать о существовании промежуточных узлов, за исключением случаев передачи конфиденциальной информации.
861 | - Унифицированный программный интерфейс сервера. Филдинг приводил URI в качестве примера формата запросов к серверу, а в качестве примера ответа сервера форматы HTML, XML и JSON, различаемые с использованием идентификаторов MIME.
862 | Филдинг указывал, что приложения, не соответствующие приведённым условиям, не могут называться REST-приложениями.
863 |
864 | ## Протоколы передачи данных
865 |
866 | `Протокол передачи данных` — набор соглашений интерфейса логического уровня, которые определяют обмен данными между различными программами. Эти соглашения задают единообразный способ передачи сообщений и обработки ошибок при взаимодействии программного обеспечения разнесённой в пространстве аппаратуры, соединённой тем или иным интерфейсом.
867 |
868 | #### IP
869 |
870 | `Internet Protocol`, межсетевой протокол - маршрутизируемый протокол сетевого уровня стека TCP/IP. Именно IP стал тем протоколом, который объединил отдельные компьютерные сети во всемирную сеть Интернет. Неотъемлемой частью протокола является адресация сети.
871 |
872 | #### TCP
873 |
874 | `Transmission Control Protocol`, протокол управления передачей — один из основных протоколов передачи данных Интернета, предназначенный для управления передачей данных в сетях и подсетях TCP/IP.
875 |
876 | #### UDP
877 |
878 | `User Datagram Protocol`, протокол пользовательских датаграмм. С UDP компьютерные приложения могут посылать сообщения (в данном случае называемые датаграммами) другим хостам по IP-сети без необходимости предварительного сообщения для установки специальных каналов передачи или путей данных. Природа UDP как протокола без сохранения состояния также полезна для серверов, отвечающих на небольшие запросы от огромного числа клиентов, например DNS и потоковые мультимедийные приложения вроде IPTV, Voice over IP, протоколы туннелирования IP и многие онлайн-игры.
879 |
880 | #### HTTP
881 |
882 | `HyperText Transfer Protocol`, протокол передачи гипертекста — протокол прикладного уровня передачи данных (изначально — в виде гипертекстовых документов). Основой HTTP является технология «клиент-сервер», то есть предполагается существование потребителей (клиентов), которые инициируют соединение и посылают запрос, и поставщиков (серверов), которые ожидают соединения для получения запроса, производят необходимые действия и возвращают обратно сообщение с результатом. Этот протокол описывает взаимодействие между двумя компьютерами (клиентом и сервером), построенное на базе сообщений, называемых запрос (Request) и ответ (Response). Каждое сообщение состоит из трех частей: стартовая строка, заголовки и тело. При этом обязательной является только стартовая строка.
883 |
884 | #### FTP
885 |
886 | `File Transfer Protocol` — это протокол передачи файлов со специального файлового сервера на компьютер пользователя. FTP дает возможность абоненту обмениваться двоичными и текстовыми файлами с любым компьютером сети. Установив связь с удаленным компьютером, пользователь может скопировать файл с удаленного компьютера на свой или скопировать файл со своего компьютера на удаленный.
887 |
888 | ## Поверхностное и глубокое копирование
889 |
890 | `Поверхностное копирование` — это просто создание нового указателя на те же самые байты в куче. То есть, в результате мы можем получить два объекта, которые указывают на одно и то же значение.
891 |
892 | Глубокое копирование:
893 | ```objectivec
894 | - (id)copyWithZone:(NSZone *)zone;
895 |
896 | @implementation Person
897 | - (id)copyWithZone:(NSZone *)zone {
898 | Person *copy = [[self class] allocWithZone:zone];
899 | copy.name = self.name;
900 | copy.age = self.age;
901 | copy.surname = self.surname;
902 | return copy;
903 | }
904 | @end
905 | ```
906 | Метод объекта класса NSArray с управлением логикой копирования:
907 | ```objectivec
908 | - (instancetype)initWithArray:(NSArray *)array copyItems:(BOOL)flag;
909 | ```
910 |
911 | ## Что такое назначенный инициализатор?
912 |
913 | Класс содержит только один основной инициализатор. Если класс содержит другие инициализаторы, то их реализация должна вызывать (прямо или косвенно) основной инициализатор.
914 | * Если класс имеет несколько инициализаторов, только один из них должен выполнять реальную работу. Этот метод называется основным инцициалuзатором. Все остальные инициализаторы должны вызывать основной инициализатор (прямо или косвенно).
915 | * Основной инициализатор вызывает основной инициализатор суперкласса перед инициализацией своих переменных экземпляров `if (self = [super...])`
916 | * Если имя основного инициализатора вашего класса отличается от имени основного инициализатора его супер класса, вы должны переопределить основной инициализатор суперкласса, чтобы он вызывал новый основной инициализатор.
917 | * Если класс содержит несколько инициализаторов, четко укажите в заголовочном файле, какой из них является основным.
918 | Установившейся практикой в таком случае является выделение среди всех init-методов одного, называемого designated initializer. Все остальные init-методы должны вызывать его и только он вызывает унаследованный init-метод.
919 |
920 | ```objectivec
921 | - (instancetype)initWithName:(const char *)theName {
922 | // call inherited method
923 | [super init];
924 | name = strdup(theName);
925 | }
926 |
927 | - (instancetype)init {
928 | return [self initWithName:@"name"];
929 | }
930 | ```
931 |
932 | ## Виды запросов
933 |
934 | ### HEAD
935 | `HEAD` Аналогичен методу GET, за исключением того, что в ответе сервера отсутствует тело. Запрос HEAD обычно применяется для извлечения метаданных, проверки наличия ресурса (валидация URL) и чтобы узнать, не изменился ли он с момента последнего обращения. Заголовки ответа могут кэшироваться. При несовпадении метаданных ресурса с соответствующей информацией в кэше копия ресурса помечается как устаревшая.
936 |
937 | ### GET
938 | `GET` Используется для запроса содержимого указанного ресурса. С помощью метода GET можно также начать какой-либо процесс. В этом случае в тело ответного сообщения следует включить информацию о ходе выполнения процесса. Клиент может передавать параметры выполнения запроса в URI целевого ресурса после символа ?:
939 | `GET /path/resource?param1=value1¶m2=value2 HTTP/1.1`
940 |
941 | ### POST
942 | `POST` Применяется для передачи пользовательских данных заданному ресурсу. Например, в блогах посетители обычно могут вводить свои комментарии к записям в HTML-форму, после чего они передаются серверу методом POST и он помещает их на страницу. При этом передаваемые данные (в примере с блогами — текст комментария) включаются в тело запроса. Аналогично с помощью метода POST обычно загружаются файлы на сервер. В отличие от метода GET, метод POST не считается идемпотентным, то есть многократное повторение одних и тех же запросов POST может возвращать разные результаты (например, после каждой отправки комментария будет появляться одна копия этого комментария). Отправить POST-запрос не так тяжело как кажется. Достаточно подготовить «правильный» NSURLRequest.
943 |
944 | ```objectivec
945 | NSString *params = @"param=value&number=1"; // задаем параметры POST запроса
946 | NSURL *url = [NSURL URLWithString:@"http://server.com"]; // куда отправлять
947 | request.HTTPMethod = @"POST";
948 | request.HTTPBody = [params dataUsingEncoding:NSUTF8StringEncoding];
949 | // следует обратить внимание на кодировку
950 | // теперь можно отправить запрос синхронно или асинхронно
951 | NSURLSession *session = [[NSURLSession alloc]initWithUrl: url];
952 | session.
953 | ```
954 |
955 | ### PUT
956 | `PUT` Применяется для загрузки содержимого запроса на указанный в запросе URI. Если по заданному URI не существовало ресурса, то сервер создаёт его и возвращает статус 201 (Created). Если же был изменён ресурс, то сервер возвращает 200 (Ok) или 204 (No Content). Сервер не должен игнорировать некорректные заголовки Content-*, передаваемые клиентом вместе с сообщением. Если какой-то из этих заголовков не может быть распознан или не допустим при текущих условиях, то необходимо вернуть код ошибки 501 (Not Implemented). Фундаментальное различие методов POST и PUT заключается в понимании предназначений URI ресурсов. Метод POST предполагает, что по указанному URI будет производиться обработка передаваемого клиентом содержимого. Используя PUT, клиент предполагает, что загружаемое содержимое соответствует находящемуся по данному URI ресурсу.
957 |
958 | ## URL and URI
959 |
960 | `Единый указатель ресурсов` (англ. URL — Uniform Resource Locator) — единообразный локатор (определитель местонахождения) ресурса. URL — это стандартизированный способ записи адреса ресурса в сети Интернет.
961 |
962 | `URI` (англ. Uniform Resource Identifier) — унифицированный (единообразный) идентификатор ресурса. URI — это символьная строка, позволяющая идентифицировать какой-либо ресурс: документ, изображение, файл, службу, ящик электронной почты и т. д. Прежде всего, речь идёт, конечно, о ресурсах сети Интернет и Всемирной паутины. URL это частный случай URI. Понятие URI включает в себя, помимо URL, например, ссылки на адреса электронной почты и т.п. URL указывает на Веб-ресурс, вроде сайта, страницы или конкретного файла, расположенных на интернет-серверах.
963 |
964 | # БД
965 |
966 | ## CoreDate
967 |
968 | ### Какие типы хранилищ поддерживает CoreData?
969 |
970 | 1. XML
971 | 2. SQLite
972 | 3. In-Memory
973 | 4. Binary
974 |
975 |
976 | ### Что такое ленивая загрузка? Что ее связывает с CoreData?
977 |
978 | Для загрузки данных из БД в память приложения удобно пользоваться загрузкой не только данных об объекте, но и о сопряжённых с ним объектах. Это делает загрузку данных проще для разработчика: он просто использует объект, который, тем не менее вынужден загружать все данные в явном виде. Но это ведёт к случаям, когда будет загружаться огромное количество сопряжённых объектов, что плохо скажется на производительности в случаях, когда эти данные реально не нужны. Паттерн `Lazy Loading `(Ленивая Загрузка) подразумевает отказ от загрузки дополнительных данных, когда в этом нет необходимости. Вместо этого ставится маркер о том, что данные не загружены и их надо загрузить в случае, если они понадобятся. Как известно, если Вы ленивы, то вы выигрываете в том случае, если дело, которое вы не делали на самом деле и не надо было делать.
979 |
980 |
981 | ### Целесообразность использования CoreData
982 |
983 | Core Data уменьшает количество кода, написанного для поддержки модели слоя приложения, как правило, на 50% - 70%, измеряемое в строках кода. Core Data имеет зрелый код, качество которого обеспечивается путем юнит-тестов, и используется ежедневно миллионами клиентов в широком спектре приложений. Структура была оптимизирована в течение нескольких версий. Она использует информацию, содержащуюся в модели и выполненяет функции, как правило, не работающие на уровне приложений в коде. Кроме того, в дополнение к отличной безопасности и обработке ошибок, она предлагает лучшую масштабируемость при работе с памятью, относительно любого конкурирующего решения. Другими словами: вы могли бы потратить долгое время тщательно обрабатывая Ваши собственные решения оптимизации для конкретной предметной области, вместо того, чтобы получить преимущество в производительности, которую Core Data предоставляет бесплатно для любого приложения.
984 |
985 | Когда нецелесообразно использовать Core Data:
986 | - Если планируется использовать очень небольшой объем данных. В этом случае проще воспользоваться для хранения Ваших данных объектами коллекций - массивами или словарями и сохранять их в plist-файлы
987 | - Если используется кроссплатформерная архитектура или требуется доступ к строго определенному формату файла с данными (хранилищу), например SQLite
988 | - Использование баз данных клиент-сервер, например MySQL или PostgreSQL
989 |
990 | ### Что такое NSManagedObjectId?
991 |
992 | `NSManagedObjectID` объект является универсальным идентификатором для управляемого объекта, а также предоставляет основу для уникальности в структуре Core Data. NSManagedObjectID – универсальный потокобезопасный идентификатор. Бывает временным и постоянным. Используется в случае передачи объекта из одного контекста в другой.
993 |
994 |
995 | ### NSFetchedResultsController
996 |
997 | `NSFetchedResultsController` представляет собой контроллер, предоставляемый фреймворком Core Data для управления запросами к хранилищу. При изменении данных в CoreData информация в таблице будет актуализироваться.
998 |
999 | NSFetchedResultsController предоставляет механизм для обработки данных (изменения, удаления, добавления) и отображает эти изменения в таблице.
1000 |
1001 |
1002 | ### Что такое контекст (Managed object context)?
1003 |
1004 | `NSManagedObjectContext` - это среда в которой находится объект и которая следит за состоянием обьекта и зависимыми объектами.
1005 |
1006 |
1007 | ### Что такое Persistent store coordinator?
1008 |
1009 | `NSPersistentStoreCoordinator` отвечает за хранение объектов данных которые передаются из NSManagedObjectContext.
1010 |
1011 |
1012 | ### Какие есть нюансы при использовании Core Data в разных потоках?
1013 |
1014 | `NSManagedObjectContext` не thread-safe read для многопоточности основная идея - создавать для каждого потока свой NSManagedObjectContext и потом синхронизировать.
1015 |
1016 | ## Realm
1017 |
1018 | ### Преимущества над другими БД
1019 |
1020 | - `Быстрая`:
1021 | Realm — невероятно быстрая библиотека для работы с базой данных. Realm быстрее, чем SQLite и CoreData (ORM-обертка над SQLite), и сравнительные тесты — лучшее доказательство для этого.
1022 | - `Кросс-платформенная`:
1023 | Файлы базы данных Realm кросс-платформенные и могут совместно использоваться iOS и Android. Независимо от того, Вы работаете с Java, Objective-C, или Swift, Вы будете использовать высокоуровневые модели.
1024 | - `Производительность`:
1025 | С позиции работоспособности было доказано что мобильная база данных Realm выполняет запросы и синхронизирует объекты значительно быстрее, чем Core Data, и осуществляет параллельный доступ к данным без проблем. Это значит, что несколько источников могут получить доступ к одному и тому же объекту без необходимости управлять блокировкой или каких-либо проблем с несогласованностью данных.
1026 | - `Шифрование`:
1027 | Мобильная база данных Realm предлагает службы шифрования для защиты базы на диске с помощью AES-256 + SHA2 64-разрядного шифрования
1028 | - `Хорошо документированная и есть отличная поддержка`:
1029 | Команда Realm предоставила читаемую, хорошо организованную документацию о Realm. Если у вас возникли проблемы, вы можете связаться с ними через Twitter, Github или Stackoverflow.
1030 | - `Бесплатная`:
1031 | Со всеми этими удивительными функциями Realm абсолютно бесплатна.
1032 |
1033 | ## SQLite
1034 | Максимальный объем хранимых данных базы SQLite составляет 2 терабайта.
1035 | Чтение из базы данных может производиться одним и более потоками, например несколько процессов могут одновременно выполнять SELECT. Однако запись в базу данных может осуществляться, только, если база в данный момент не занята другим процессом.
1036 | SQLite не накладывает ограничения на типы данных. Любые данные могут быть занесены в любой столбец. Ограничения по типам данных действуют только на INTEGER PRIMARY KEY, который может содержать только 64-битное знаковое целое.
1037 | SQLite версии 3.0 и выше позволяет хранить BLOB данные в любом поле, даже если оно объявлено как поле другого типа. Обращение к SQLite базе из двух потоков одновременно неизбежно вызовет краш. Выхода два:
1038 |
1039 | Синхронизируйте обращения при помощи директивы @synchronized.
1040 | Если задача закладывается на этапе проектирования, завести менеджер запросов на основе NSOperationQueue. Он страхует от ошибок автоматически, а то, что делается автоматически, часто делается без ошибок.
1041 | Пример SQLite:
1042 |
1043 | ```objectivec
1044 | - (int)createTable:(NSString *)filePath {
1045 | sqlite3 *db = NULL;
1046 | int rc = 0;
1047 |
1048 | rc = sqlite3_open_v2([filePath cStringUsingEncoding:NSUTF8StringEncoding], &db, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL);
1049 | if (SQLITE_OK != rc) {
1050 | sqlite3_close(db);
1051 | NSLog(@"Failed to open db connection");
1052 | } else {
1053 | char *query ="CREATE TABLE IF NOT EXISTS students (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, age INTEGER, marks INTEGER)";
1054 | char *errMsg;
1055 | rc = sqlite3_exec(db, query, NULL, NULL, &errMsg);
1056 | if (SQLITE_OK != rc) {
1057 | NSLog(@"Failed to create table rc:%d, msg=%s",rc,errMsg);
1058 | }
1059 | sqlite3_close(db);
1060 | }
1061 | return rc;
1062 | }
1063 | ```
1064 |
1065 | # Многопоточность
1066 |
1067 | ## Runloop
1068 |
1069 | В Cocoa для каждого потока системой обычно создается свой Run Loop — цикл, который обрабатывает таймеры и события, а так же усыпляет поток, если ему нечего делать в текущий момент.
1070 | Run Loop поддерживает 2 типа событий:
1071 | 1. `Input sources` — асинхронные события. Обычно это сообщения от других потоков, приложений или системных вызовов.
1072 | 2. `Timer sources` — синхронные события. Таймеры. Вызываются синхронно с известным интервалом.
1073 | Каждый Run Loop определяет режим, в котором он работает: от режима зависит, какие события будут обработаны и кто будет об этом оповещен
1074 |
1075 |
1076 | ## Способы достижения многопоточности в iOS и macOS
1077 |
1078 | Существует три способа достижения параллелизма в iOS:
1079 | 1. Потоки (threads)
1080 | 2. GCD
1081 | 3. NSOperationQueue
1082 |
1083 | Недостатком потоков является то, что они немасштабируемы для разработчика. Вы должны решить, сколько потоков нужно создать и изменять их число динамически в соответствии с условиями. Кроме того, приложение принимает на себя большую часть затрат, связанных с созданием и встраиванием потоков, которые оно использует.
1084 |
1085 | Поэтому в macOS и iOS предпочтительно использовать асинхронный подход к решению проблемы параллелизма, а не полагаться на потоки.
1086 |
1087 | Одной из технологий асинхронного запуска задач является Grand Central Dispatch (GCD), которая отводит управление потоками до уровня системы. Все, что разработчик должен сделать, это определить выполняемые задачи и добавить их в соответствующую очередь отправки. GCD заботится о создании необходимых потоков и время для работы в этих потоках.
1088 |
1089 | Все dispatch queues представляют собой структуры данных FIFO, поэтому задачи всегда запускаются в том же порядке, в котором они добавлены.
1090 |
1091 | В отличие от dispatch queue очереди операций (NSOperation Queue) не ограничиваются выполнением задач в порядке FIFO и поддерживают создание сложных графиков выполнения заказов для ваших задач.
1092 |
1093 |
1094 | ## Что такое deadlock?
1095 |
1096 | `Deadlock` — ситуация в многозадачной среде, при которой несколько процессов находятся в состоянии бесконечного ожидания ресурсов, захваченных самими этими процессами.
1097 | ```objectivec
1098 | dispatch_queue_t queue = dispatch_queue_create("my.label", DISPATCH_QUEUE_SERIAL);
1099 | dispatch_async(queue, ^{
1100 | dispatch_sync(queue, ^{
1101 | // outer block is waiting for this inner block to complete,
1102 | // inner block won't start before outer block finishes
1103 | // => deadlock
1104 | });
1105 |
1106 | // this will never be reached
1107 | })
1108 | ```
1109 |
1110 |
1111 | ## Что такое livelock?
1112 |
1113 | `Livelock` частая проблема в асинхронных системах. Потоки почти не блокируются на критических ресурсах. Вместо этого они выполняют свою небольшую неблокируемую задачу и отправляют её в очередь на обработку другими потоками. Может возникнуть ситуация, когда потоки друг другу начинают перекидывать какое-то событие и его обработка зацикливается. Явного бесконечного цикла, как бы, не происходит, но нагрузка на асинхронную систему резко возрастает. В результате чего эти потоки больше ничем не успевают занимаются.
1114 |
1115 |
1116 | ## Что такое DispatchGroup?
1117 |
1118 | `DispatchGroup` уведомляют вас, когда вся группа задач завершена. Эти задачи могут быть синхронными или асинхронными и могут даже быть отслежены из разных очередей. DispatchGroup также уведомляют вас о синхронности или асинхронности, когда все события группы завершены. Так как элементы отслеживаются в различных очередях, то экземпляр dispatch_group_t отслеживает различные задачи в очередях.
1119 |
1120 |
1121 | ## Разница между синхронными и асинхронными задачами, однопоточностью и многопоточностью
1122 |
1123 | Ниже описаны термины в привязке к GCD, но с небольшими изменениями они верны и для программирования в целом.
1124 |
1125 | `Синхронная операция` начинает выполнятся сразу при вызове, блокирует поток. Выполняется в текущем потоке.
1126 | `Асинхронная операция` ставит задачу в очередь выполнения, продолжает выполнение кода, из которого вызвана задача. Если очередь однопоточная, то задача будет выполнятся после выполнения всех задач, которые уже поставлены в очередь, если много поточная - возможно ее выполнение в другом потоке.
1127 |
1128 | Нужно запомнить, что синхронность-асинхронность и однопоточность-многопоточность две пары разных характеристить, и одни не зависят от других (и синхронность и асинхронность могут работать как в однопоточной среде, так и в многопоточной)
1129 |
1130 |
1131 | ## Зачем использовать synchronized?
1132 |
1133 | `@synchronized` гарантирует, что только один поток может выполнять этот код в блоке в любой момент времени.
1134 |
1135 |
1136 | ## Что такое мьютекс (mutex)?
1137 |
1138 | `Мьютекс` является одним из видов семафора, который предоставляет доступ одновременно только одному потоку. Если мьютекс используется и другой поток пытается получить его, что поток блокируется до тех пор, пока мьютекс не освободится от своего первоначального владельца. Если несколько потоков соперничают за одни и те же мьютексы, только одному будет разрешен к нему доступ.
1139 |
1140 |
1141 | ## Что такое семафор (semafor)?
1142 |
1143 | Семафор позволяет выполнять какой-либо участок кода одновременно только конкретному количеству потоков. В основе семафора лежит счетчик, который и определяет, можно ли выполнять участок кода текущему потоку или нет. Если счетчик больше нуля — поток выполняет код, в противном случае — нет. В GCD выглядит так:
1144 | `semaphore_create` – создание семафора (аналог sem_init)
1145 | `semaphore_destroy` – удаление, соответственно (аналог sem_destroy)
1146 | `semaphore_wait` – блокирующее ожидание на семафоре (аналог sem_wait)
1147 | `semaphore_signal` – освобождение семафора (аналог sem_post)
1148 |
1149 | # Тестирование
1150 |
1151 | ## Unit-тесты
1152 |
1153 | `Модульное тестирование`, или юнит-тестирование (англ. unit testing) — процесс в программировании, позволяющий проверить на корректность отдельные модули исходного кода программы.
1154 |
1155 | Идея состоит в том, чтобы писать тесты для каждой нетривиальной функции или метода. Это позволяет достаточно быстро проверить, не привело ли очередное изменение кода к регрессии, то есть к появлению ошибок в уже оттестированных местах программы, а также облегчает обнаружение и устранение таких ошибок.
1156 |
1157 | ## TDD
1158 |
1159 | `Test-Driven Development` («разработка через тестирование») – это специальная методика разработки ПО, которая основывается на коротких циклах работы, где сначала создаётся тест, а потом функционал.
1160 |
1161 | Создавая тесты до реализации кода, мы создаем модель предметной области в уме, управляем процессом разработки кода, и, наконец, обеспечиваем себя средствами для автоматической проверки корректности кода. В результате мы получаем более безопасный, структурированный, легко читаемый код, уменьшаем количество дефектов и т.д. Этот способ программирования полностью отличается от тех, к которым мы привыкли, и намного приятнее.
1162 |
1163 |
1164 | # Задания
1165 |
1166 |
1167 | ## Какой метод вызовется: класса A или класса B?
1168 |
1169 | ```objectivec
1170 | @interface A : NSObject
1171 | - (void)someMethod;
1172 | @end
1173 |
1174 | @implementation A
1175 | - (void)someMethod {
1176 | NSLog(@"This is class A");
1177 | }
1178 | @end
1179 |
1180 | @interface B : A
1181 | @end
1182 |
1183 | @implementation B
1184 | - (void)someMethod {
1185 | NSLog(@"This is class B");
1186 | }
1187 | @end
1188 |
1189 | @interface C : NSObject
1190 | @end
1191 |
1192 | @implementation C
1193 | - (void)method {
1194 | A *a = [B new];
1195 | [a someMethod];
1196 | }
1197 | @end
1198 | ```
1199 |
1200 | Ответ: вызовется метод класса B.
1201 |
1202 |
1203 | ## Что выведется в консоль?
1204 |
1205 | ```objectivec
1206 | NSObject *object = [NSObject new];
1207 | dispatch_async(dispatch_get_main_queue(), ^ {
1208 | NSLog(@"A %d", [object retainCount]);
1209 | dispatch_async(dispatch_get_main_queue(), ^ {
1210 | NSLog(@"B %d", [object retainCount]);
1211 | });
1212 | NSLog(@"C %d", [object retainCount]);
1213 | });
1214 | NSLog(@"D %d", [object retainCount]);
1215 | ```
1216 |
1217 | Ответ:
1218 | ```
1219 | D 2
1220 | A 2
1221 | C 3
1222 | B 2
1223 | ```
1224 |
1225 |
1226 | ## Нужно сделать повторяемый таймер, который вызывается каждую минуту в бекграунде. Как это сделать?
1227 |
1228 | Пояснение к заданию:
1229 | Прицельная точность тиков не важна, достаточно некая периодичность.
1230 |
1231 | Решение:
1232 | Если надо сделать таймер в фоне, то стоит выбирать поток с бегущим ранлупом. Либо воспользоваться уже готовым решением для GCD.
1233 | ```objectivec
1234 | dispatch_source_t CreateDispatchTimer(uint64_t interval, uint64_t leeway, dispatch_queue_t queue, dispatch_block_t block) {
1235 | dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
1236 | if (timer) {
1237 | dispatch_source_set_timer(timer, dispatch_walltime(NULL, 0), interval, leeway);
1238 | dispatch_source_set_event_handler(timer, block);
1239 | dispatch_resume(timer);
1240 | }
1241 | return timer;
1242 | }
1243 | ```
1244 |
1245 | ## Что произойдет после запуска приложения?
1246 |
1247 | ```objectivec
1248 | func application(_ application: UIApplication, didFinishLaunchingWithOptions...) -> Bool {
1249 | DispatchQueue.global().async {
1250 | Timer.scheduledTimer(timeInterval: 0.4, target: self,
1251 | selector: #selector(self.tickTimer),
1252 | userInfo: nil, repeats: true)
1253 | }
1254 | return true
1255 | }
1256 |
1257 | func tickTimer() {
1258 | print("Tick-Tack")
1259 | }
1260 | ```
1261 |
1262 | Решение:
1263 | Ничего не произойдет. Ранлуп не взведен. А еще будет небольшая утечка памяти.
1264 | Для исправления ошибки нужно выбирать бегущий ранлуп или использовать функцию sync
1265 |
--------------------------------------------------------------------------------