Swiftyinsta: рд╡реЗрдмрд▓реЙрдЧрд┐рди рдХрд╛рдо рдирд╣реАрдВ рдХрд░ рд░рд╣рд╛

рдХреЛ рдирд┐рд░реНрдорд┐рдд 22 рдЬреБрд▓ре░ 2019  ┬╖  16рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ  ┬╖  рд╕реНрд░реЛрдд: TheM4hd1/SwiftyInsta

рдкреЙрдб рд╡реЗрдмрд▓реЙрдЧрд┐рди рдХреЛ рдЕрдкрдбреЗрдЯ рдХрд░рдиреЗ рдХреЗ рдмрд╛рдж рдЖрдИрдУрдПрд╕ 10 рд╕рдВрд╕реНрдХрд░рдг рдореЗрдВ рд╕рдВрдХрд▓рд┐рдд рдирд╣реАрдВ рдХрд┐рдпрд╛ рдЧрдпрд╛ред
рдЬрдм рдореИрдВ рдЖрдИрдУрдПрд╕ рдХреЗ 11.0 рд╕рдВрд╕реНрдХрд░рдг рдореЗрдВ рдмрджрд▓рддрд╛ рд╣реВрдВ рддреЛ рдпрд╣ рдХрд╣рддрд╛ рд╣реИ:

  • 'loginDelegate' рдкрджрд╛рд╡рдирдд рд╣реИ: рдЗрд╕рдХреЗ рдмрдЬрд╛рдп InstagramLoginWebView рдЧреБрдгреЛрдВ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВред
  • 'InstagramLoginWebViewDelegate' рдХреЛ рд╣рдЯрд╛ рджрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ: рдЗрд╕рдХреЗ рдмрдЬрд╛рдп InstagramLoginWebViewProtocol рдХреНрд▓реЛрдЬрд░ рдкреНрд░реЙрдкрд░реНрдЯреАрдЬ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВред

рдЬрдм рдореИрдВрдиреЗ InstagramLoginWebViewDelegate рдХреЛ InstagramLoginWebViewProtocol рдореЗрдВ рдмрджрд▓ рджрд┐рдпрд╛:

  • 'InstagramLoginWebViewProtocol' рдХреЗ рд▓рд┐рдП рдЖрд╡рд╢реНрдпрдХ рд╣реИ рдХрд┐ 'LoginViewController' рдХреЛ 'UIView' рд╕реЗ рдЗрдирд╣реЗрд░рд┐рдЯ рдХрд┐рдпрд╛ рдЬрд╛рдП

рдореЗрд░реЗ рдХреЛрдб:

рдХреНрд▓рд╛рд╕ рд▓реЙрдЧ рдЗрди рд╡реНрдпреВ рдХрдВрдЯреНрд░реЛрд▓рд░: UIViewController {

var loginWebView: InstagramLoginWebView! = nil

override func viewDidLoad() {
    super.viewDidLoad()

    loginWebView = InstagramLoginWebView(frame: self.view.frame)
    self.view.addSubview(loginWebView!)
    loginWebView?.loginDelegate = self **-- Cannot assign value of type 'LoginViewController' to type 'InstagramLoginWebViewDelegate?'**
    self.loginWebView?.loadInstagramLogin(isNeedPreloadForCookieSync: true) **--Argument passed to call that takes no arguments**
}

}

рдПрдХреНрд╕рдЯреЗрдВрд╢рди LoginViewController: InstagramLoginWebViewProtocol { --'InstagramLoginWebViewProtocol' рдХреЗ рд▓рд┐рдП рдЖрд╡рд╢реНрдпрдХ рд╣реИ рдХрд┐ 'LoginViewController' рдХреЛ 'UIView' рд╕реЗ рдЗрдирд╣реЗрд░рд┐рдЯ рдХрд┐рдпрд╛ рдЬрд╛рдП

func userLoggedSuccessfully() {
    print("User Logged Successfully")

    DispatchQueue.main.async {
        self.loginWebView.removeFromSuperview()
    }

}

рд╕рднреА 16 рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ

рдЕрд░реЗ @effecttwins

InstagramLoginWebView рдкрд┐рдЫрд▓реЗ рдЕрдкрдбреЗрдЯ рдореЗрдВ рдмрд╣реБрдд рдмрджрд▓ рдЧрдпрд╛ рд╣реИ, рдФрд░ рдЕрд╕рдВрдЧрддрд┐ рдХреЗ рдХрд╛рд░рдг iOS 10.* рд▓рд┐рдП рд╕рдорд░реНрдерди
loginDelegate рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХрд╛ рдЕрдм рд╕реБрдЭрд╛рд╡ рдирд╣реАрдВ рджрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ, рд╣рд╛рд▓рд╛рдВрдХрд┐ рдпрд╣ рдЕрднреА рднреА рдХрд╛рд░реНрдпрд╛рддреНрдордХ рд╣реИред
рдЖрдк рдЬрд┐рд╕ рд╡реНрдпрд╡рд╣рд╛рд░ рдХреЗ рдЖрджреА рд╣реИрдВ, рдЙрд╕реЗ рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЖрдкрдХреЛ рдХреЗрд╡рд▓ рдЕрдкрдиреЗ loginWebView рдкрд░ рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рдЧреБрдг рд╕реЗрдЯ рдХрд░рдирд╛ рд╣реИ:

  • didReachEndOfLoginFlow рдПрдХ _рдХреНрд▓реЛрдЬрд░_ рд╣реИ рдЬрд┐рд╕реЗ redirected рдЗрд╕реНрддреЗрдорд╛рд▓ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред
  • didSuccessfullyLogIn _delegate_ рдХреЗ userLoggedSuccessfully() рдХреА рдЬрдЧрд╣ рдПрдХ _рдХреНрд▓реЛрдЬрд░_ рд╣реИред
  • completionHandler , _delegate_ рдХреЗ webViewFinishedToLoadUser(sessionChache:handler:) рдХреА рдЬрдЧрд╣ рдПрдХ _рдХреНрд▓реЛрдЬрд░_ рд╣реИ

рдпрд╣ 1.7.* рдХреЗ рд▓рд┐рдП рдЕрджреНрдпрддрди рдХреЛрдб рд╣реИред

class LoginViewController: UIViewController {
    var loginWebView: InstagramLoginWebView!

    override func viewDidLoad() {
        super.viewDidLoad()

        loginWebView = InstagramLoginWebView(frame: self.view.frame,
                                             didSuccessfullyLogIn: { [weak self] in DispatchQueue.main.async { self?.loginWebView.removeFromSuperview() }},
                                             completionHandler: { sessionCache, handler in /* do whaterver you need to */ })
        view.addSubview(loginWebView)
        loginWebView.loadInstagramLogin()
    }
}

рдЗрд╕рд▓рд┐рдП рдЬрдм рдореИрдВ рдПрдХреНрд╕рдЯреЗрдВрд╢рди InstagramLoginWebViewDelegate рдХреЛ InstagramLoginWebViewProtocol рдореЗрдВ рдмрджрд▓рддрд╛ рд╣реВрдВ рдФрд░ рдпрд╣ рдХрд╣рддрд╛ рд╣реИ: 'InstagramLoginWebViewProtocol' рдХреЗ рд▓рд┐рдП рдЖрд╡рд╢реНрдпрдХ рд╣реИ рдХрд┐ 'LoginViewController' 'UIView' рд╕реЗ рдкреНрд░рд╛рдкреНрдд рд╣реЛред

рдХреЛрдб:

рдПрдХреНрд╕рдЯреЗрдВрд╢рди рд▓реЙрдЧрд┐рди рд╡реНрдпреВ рдХрдВрдЯреНрд░реЛрд▓рд░: InstagramLoginWebViewDelegate {

func userLoggedSuccessfully() {
    print("User Logged Successfully")

}

func webViewFinishedToLoadUser(sessionCache: SessionCache, handler: APIHandlerProtocol) {
    print("Loading user with sessioncache is successful")

    do{
        let encoder = JSONEncoder()
        let data = try encoder.encode(sessionCache)

        let sessionCacheString = String(data: data, encoding: .utf8)

    }catch {
        print("Whoops, an error occured: \(error)")
    }


}

рдЖрдкрдХреЛ рдХрднреА рднреА InstagramLoginWebViewProtocol рдЕрдиреБрд░реВрдк рдирд╣реАрдВ рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдПред
рдЗрд╕реЗ internal рдЪрд┐рд╣реНрдирд┐рдд рдирд╣реАрдВ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдореЗрд░реА рдЧрд▓рддреА рд╣реИред рдореИрдВ рдХреНрд╖рдорд╛рдкреНрд░рд╛рд░реНрдереА рд╣реВрдВред

рдпрд╣ рд╡рд╣ рд╕рдм рдХреЛрдб рд╣реИ рдЬрд┐рд╕рдХреА рдЖрдкрдХреЛ рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред рдирд╣реАрдВ InstagramLoginWebViewProtocol ред рдирд╣реАрдВ InstagramLoginWebViewDelegate ред

import UIKit
import SwiftyInsta

class LoginViewController: UIViewController {
    var loginWebView: InstagramLoginWebView!

    override func viewDidLoad() {
        super.viewDidLoad()

        loginWebView = InstagramLoginWebView(frame: view.frame,
                                             didReachEndOfLoginFlow: nil,
                                             didSuccessfullyLogIn: { [weak self] in
                                                // I would actually put this in `didReachEndOfLoginFlow`,
                                                // so the user never sees their timeline blinking.
                                                DispatchQueue.main.async {
                                                    self?.loginWebView.removeFromSuperview()
                                                }
            },
                                             completionHandler: { sessionCache, _ in
                                                print("Loading user with sessioncache is successful")

                                                do {
                                                    let encoder = JSONEncoder()
                                                    let data = try encoder.encode(sessionCache)

                                                    let sessionCacheString = String(data: data, encoding: .utf8)
                                                } catch {
                                                    print("Whoops, an error occured: \(error)")
                                                }
        })
        view.addSubview(loginWebView)
        loginWebView.loadInstagramLogin()
    }
}

@sbertix рдЖрдкрдХреА рд╕рднреА рдорджрдж рдХреЗ рд▓рд┐рдП рдзрдиреНрдпрд╡рд╛рджред
рд▓реЗрдХрд┐рди рдЗрдВрд╕реНрдЯрд╛рдЧреНрд░рд╛рдо рд▓реЙрдЧрд┐рди рдкреЗрдЬ рд▓реЛрдб рдирд╣реАрдВ рд╣реБрдЖ рд╣реИ, рд╕реНрдХреНрд░реАрди рдореЗрдВ рдХреЗрд╡рд▓ рд╕рдлреЗрдж рдкреЗрдЬ рд╣реИ

рдпрд╣ рд╡рд╣ рд╕рдм рдХреЛрдб рд╣реИ рдЬрд┐рд╕рдХреА рдЖрдкрдХреЛ рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред рдирд╣реАрдВ InstagramLoginWebViewProtocol ред рдирд╣реАрдВ InstagramLoginWebViewDelegate ред

@effecttwins рдореЗрд░реЗ рджреНрд╡рд╛рд░рд╛ рдКрдкрд░ рд▓рд┐рдЦреЗ рдЧрдП рдХреЛрдб рдХреЛ рдХреЙрдкреА рдФрд░ рдкреЗрд╕реНрдЯ рдХрд░реЗрдВред loadInstagramLogin() рдкрд░ рдХреЙрд▓ рдХрд░рдирд╛ рди рднреВрд▓реЗрдВред
рдпрд╣ рд╕рдЪрдореБрдЪ рдЖрдкрдХреЗ рд▓рд┐рдП рдкрд╣рд▓реЗ рд╕реЗ рд╣реА рд▓рд╛рдЧреВ рд╣реИ
рдпрд╣ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИрдВ

рд╣рд╛рдБ рдореИрдВрдиреЗ рд╕рднреА рдХреЛрдб рдХреЙрдкреА рдФрд░ рдкреЗрд╕реНрдЯ рдХрд┐рдпрд╛ рдФрд░ рд▓реЛрдбрдЗрдВрд╕реНрдЯрд╛рдЧреНрд░рд╛рдорд▓реЙрдЧрд┐рди рдХрд╣рд╛ :)
InstagramLoginWebViewProtocol рдФрд░ InstagramLoginWebViewDelegate рдХреЛ рднреА рд╣рдЯрд╛ рджрд┐рдпрд╛ рд╣реИ

рдХрдВрд╕реЛрд▓ рдореЗрдВ рдореБрдЭреЗ рдпрд╣ рддреНрд░реБрдЯрд┐ рдорд┐рд▓ рд░рд╣реА рд╣реИ, рдореБрдЭреЗ рдпрдХреАрди рдирд╣реАрдВ рд╣реИ рдХрд┐ рдпрд╣ рдЗрд╕ рдкрд░рд┐рдпреЛрдЬрдирд╛ рд╕реЗ рд╕рдВрдмрдВрдзрд┐рдд рд╣реИ рдпрд╛ рдирд╣реАрдВ
рд╕реЗрд╡рд╛ рд╕рдВрдХреЗрдд рдирд╣реАрдВ рдХрд░ рд╕рдХрд╛ com.apple.WebKit.Networking: 113: рдирд┐рд░реНрджрд┐рд╖реНрдЯ рд╕реЗрд╡рд╛ рдирд╣реАрдВ рдорд┐рд▓ рд╕рдХрд╛

рдХреНрд╖рдорд╛ рдХрд░реЗрдВ, рдореИрдВрдиреЗ рдЕрдкрдиреЗ рдХреЛрдб рд╣рд╛рд╣рд╛рд╣рд╛ рдореЗрдВ loginWebView рдХреЛ view рдореЗрдВ рдХрднреА рдирд╣реАрдВ рдЬреЛрдбрд╝рд╛ рд╣реИ
рдореИрдВрдиреЗ рдЗрд╕реЗ рд╕рдВрдкрд╛рджрд┐рдд рдХрд┐рдпрд╛ рд╣реИред рдЗрд╕реЗ рдлрд┐рд░ рд╕реЗ рдЬрд╛рдВрдЪреЗрдВред рдЗрд╕реЗ рдЕрдм рдХрд╛рдо рдХрд░рдирд╛ рдЪрд╛рд╣рд┐рдП @effecttwins

рдЖрдк рдХрдорд╛рд▓ рд╣реИрдВ @sbertix
рдпрд╣ рдЕрдм рдХрд╛рдо рдХрд░ рд░рд╣рд╛ рд╣реИ
рдЖрдк рд╕рднреА рдХреА рдорджрдж рдХреЗ рд▓рд┐рдП рдзрдиреНрдпрд╡рд╛рдж

рдЕрд░реЗ @sbertix

рдХреНрдпрд╛ рд╣реЛрддрд╛ рд╣реИ рдореИрдВ рдПрдорд╡реАрд╡реАрдПрдо рдкреИрдЯрд░реНрди рдХрд╛ рдкрд╛рд▓рди рдХрд░ рд░рд╣рд╛ рд╣реВрдВ рдФрд░ рдореЗрд░рд╛ рд╡рд┐рдЪрд╛рд░ рдФрд░ рдореЗрд░рд╛ рд╡реНрдпреВ рдХрдВрдЯреНрд░реЛрд▓рд░ рдЕрд▓рдЧ-рдЕрд▓рдЧ рдлрд╛рдЗрд▓реЛрдВ рдореЗрдВ рд╣реИ? рд╡реНрдпреВ рдХрдВрдЯреНрд░реЛрд▓рд░ рдХреЛ рдбреЗрдЯрд╛ рдирд╣реАрдВ рднреЗрдЬрдирд╛ рдЪрд╛рд╣рд┐рдПред рдХреНрдпрд╛ InstagramLoginWebView рдХреЗ рдкреНрд░рд╛рд░рдВрдн рд╣реЛрдиреЗ рдХреЗ рдмрд╛рдж didSuccessfullyLogIn рдлрд╝рдВрдХреНрд╢рди рддрдХ рдкрд╣реБрдВрдЪ рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдХрд╛ рдХреЛрдИ рддрд░реАрдХрд╛ рд╣реИ?

рдЖрдкрдХреЛ init InstagramLoginWebView рд╕рд╛рде didSuccessfullyLogIn (рдпрд╣ рд╡реИрдХрд▓реНрдкрд┐рдХ рд╣реИ) рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдирд╣реАрдВ рд╣реИред
рдФрд░ рдЕрдиреНрдп _рдХреНрд▓реЛрдЬрд░_ рдХреЗ рд╕рд╛рде рднреА: рдПрдХ рдмрд╛рд░ рдЖрдкрдХреЗ рдкрд╛рд╕ рдПрдХ рдЕрд▓рдЧ рдорд╛рди рдЕрд╕рд╛рдЗрди рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред
@anonrig

рдХреНрдпрд╛ рдЖрдк рдЗрд╕рдХрд╛ рдПрдХ рдЙрджрд╛рд╣рд░рдг рдкреНрд░рджрд╛рди рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ, рдЕрдЧрд░ рдореИрдВ рдкреВрдЫ рд╕рдХрддрд╛ рд╣реВрдБ? @sbertix :)

рдЬрд╝рд░реВрд░ред рдХреНрдпрд╛ рдЖрдк рдЕрдкрдиреЗ рдХреЛрдб рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдЕрдзрд┐рдХ рдЬрд╛рдирдХрд╛рд░реА рднреЗрдЬ рд╕рдХрддреЗ рд╣реИрдВ? рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдЬрд┐рд╕ рддрд░рд╣ рд╕реЗ рдЖрдкрдХрд╛ рдореЙрдбрд▓ рдФрд░ рджреГрд╢реНрдп рд╕реЗрдЯрдЕрдк рд╣реИред

рд╣рд╛рдБ рдмреЗрд╢рдХ!

1.7.x рд╕реЗ рдкрд╣рд▓реЗ рдореИрдВ delegates рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ ViewController рд╕реНрддрд░ рдкрд░ рд▓реЙрдЧрд┐рди рд╕рдлрд▓рддрд╛ рдХрд╛рд░реНрдпрдХреНрд░рдо рдХреЛ рд╕рдВрднрд╛рд▓ рд░рд╣рд╛ рдерд╛

рдЙрджрд╛рд╣рд░рдг рджреГрд╢реНрдп:

final class LoginWebView: UIView {
    // MARK: - Properties
    var bag = DisposeBag()

    private(set) lazy var webView: InstagramLoginWebView = InstagramLoginWebView(frame: UIScreen.main.bounds)

    private(set) lazy var closeButtonLabel: UILabel = {
        let label: UILabel = .create(text: "Close".localized(), numberOfLines: 1, textAlignment: .center, textColor: .white, font: .light(size: 16))
        label.isUserInteractionEnabled = true
        return label
    }()

    private(set) lazy var closeButtonBarItem: UIBarButtonItem = UIBarButtonItem(customView: closeButtonLabel)

    // MARK: - Initialization
    init() {
        super.init(frame: .zero)

        [webView].forEach(addSubview(_:))

        webView.snp.makeConstraints { make in
            make.edges.equalToSuperview()
        }
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

рдЙрджрд╛рд╣рд░рдг рд╡реНрдпреВ рдХрдВрдЯреНрд░реЛрд▓рд░:

final class LoginWebViewController: UIViewController, View, ErrorDisplayer {
    // MARK: - Properties
    private lazy var viewSource = LoginWebView()

    private(set) var bag: DisposeBag
    private(set) var viewModel: LoginWebViewModel
    private(set) var completionObservable = PublishSubject<(SessionCache?, APIHandlerProtocol?)?>()

    // MARK: - Initialization
    init() {
        bag = DisposeBag()
        viewModel = LoginWebViewModel()

        super.init(nibName: nil, bundle: nil)

        bindErrorHandling()
        observeDatasource()
    }

    // MARK: - Life cycle
    override func loadView() {
        view = viewSource
        view.backgroundColor = .white
    }

    override func viewDidLoad() {
        super.viewDidLoad()

        viewSource.webView.loginDelegate = self
        viewSource.webView.loadInstagramLogin(isNeedPreloadForCookieSync: true)

        // viewSource.webView.didSuccessfullyLogIn
        configureNavBar(with: "Login".localized(), prefersLargeTitle: false)

        navigationItem.rightBarButtonItem = viewSource.closeButtonBarItem
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

рдореИрдВ рдареАрдХ рд╕реЗ рдирд╣реАрдВ рдЬрд╛рдирддрд╛ рдХрд┐ LoginWebViewModel рд╣реИ... рд▓реЗрдХрд┐рди рдЕрдЧрд░ рдЙрджреНрджреЗрд╢реНрдп рд╕рдм рдХреБрдЫ completeObservable рддреЛ рдЖрдк рдмрд╕ рдпрд╣ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ:

final class LoginWebView: UIView {
    // MARK: - Properties
    var bag = DisposeBag()

    private(set) lazy var webView: InstagramLoginWebView = InstagramLoginWebView(frame: UIScreen.main.bounds, completionHandler: nil)

    private(set) lazy var closeButtonLabel: UILabel = {
        let label: UILabel = .create(text: "Close".localized(), numberOfLines: 1, textAlignment: .center, textColor: .white, font: .light(size: 16))
        label.isUserInteractionEnabled = true
        return label
    }()

    private(set) lazy var closeButtonBarItem: UIBarButtonItem = UIBarButtonItem(customView: closeButtonLabel)

    // MARK: - Initialization
    init() {
        super.init(frame: .zero)

        [webView].forEach(addSubview(_:))

        webView.snp.makeConstraints { make in
            make.edges.equalToSuperview()
        }
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}
final class LoginWebViewController: UIViewController, View, ErrorDisplayer {
    // MARK: - Properties
    private lazy var viewSource = LoginWebView()

    private(set) var bag: DisposeBag
    private(set) var viewModel: LoginWebViewModel
    private(set) var completionObservable = PublishSubject<(SessionCache?, APIHandlerProtocol?)?>()

    // MARK: - Initialization
    init() {
        bag = DisposeBag()
        viewModel = LoginWebViewModel()

        super.init(nibName: nil, bundle: nil)

        bindErrorHandling()
        observeDatasource()
    }

    // MARK: - Life cycle
    override func loadView() {
        view = viewSource
        view.backgroundColor = .white
    }

    override func viewDidLoad() {
        super.viewDidLoad()

        viewSource.webView.completionHandler = { [weak self] cache, handler in
            self?.completionObservable.accept((cache, handler))
        }
        viewSource.webView.loadInstagramLogin()

        // viewSource.webView.didSuccessfullyLogIn
        configureNavBar(with: "Login".localized(), prefersLargeTitle: false)

        navigationItem.rightBarButtonItem = viewSource.closeButtonBarItem
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

рдореИрдВрдиреЗ InstagramLoginWebView init(frame:) рдХреЛ init(frame:completionHandler:) рдФрд░ рдлрд┐рд░ рдЖрдкрдХреЗ рд╡рд┐рд╖рдп рдореЗрдВ рдореВрд▓реНрдпреЛрдВ рдХреЛ рдЖрдЧреЗ рдмрдврд╝рд╛рдиреЗ рдХреЗ рд▓рд┐рдП completionHandler рдХреЛ рдЕрдкрдбреЗрдЯ рдХрд┐рдпрд╛ рд╣реИред

рдзрдиреНрдпрд╡рд╛рдж @sbertix

рдХреНрдпрд╛ рдпрд╣ рдкреГрд╖реНрда рдЙрдкрдпреЛрдЧреА рдерд╛?
0 / 5 - 0 рд░реЗрдЯрд┐рдВрдЧреНрд╕