Làm cách nào để bạn chia sẻ dữ liệu giữa bộ điều khiển chế độ xem và các đối tượng khác trong Swift?


88

Giả sử tôi có nhiều bộ điều khiển chế độ xem trong ứng dụng Swift của mình và tôi muốn có thể chuyển dữ liệu giữa chúng. Nếu tôi giảm nhiều cấp trong ngăn xếp bộ điều khiển chế độ xem, làm cách nào để chuyển dữ liệu sang bộ điều khiển chế độ xem khác? Hoặc giữa các tab trong bộ điều khiển chế độ xem thanh tab?

(Lưu ý, câu hỏi này là một "chuông".) Nó được hỏi nhiều đến mức tôi quyết định viết một bài hướng dẫn về chủ đề này. Xem câu trả lời của tôi dưới đây.


1
Hãy thử googling cho đại biểu
milo526

4
Tôi đã đăng bài này để tôi có thể cung cấp giải pháp cho 10.000 trường hợp của câu hỏi này xuất hiện mỗi ngày trên SO. Xem câu trả lời tự của tôi. :)
Duncan C

Xin lỗi tôi đã quá nhanh chóng với phản ứng :) tốt để có thể liên kết đến :) này
milo526

2
Đừng lo lắng. Bạn nghĩ tôi là # 10.001, phải không? <grin>
Duncan C

4
@DuncanC Tôi không thích câu trả lời của bạn. :( Không sao đâu-không phải là một câu trả lời cho tất cả các tình huống ... không sao cả, nó sẽ hoạt động cho mọi tình huống, nhưng nó cũng không phải là cách tiếp cận phù hợp cho hầu hết mọi tình huống. Mặc dù vậy, chúng tôi đã hiểu nó trong đầu ? mà đánh dấu bất kỳ câu hỏi về chủ đề như là một bản sao của một đây là một ý tưởng tốt Xin vui lòng, thì không.
nhgrif

Câu trả lời:


91

Câu hỏi của bạn rất rộng. Để gợi ý rằng có một giải pháp đơn giản cho mọi tình huống là một chút ngây thơ. Vì vậy, chúng ta hãy xem xét một số tình huống này.


Theo kinh nghiệm của tôi, kịch bản phổ biến nhất được hỏi về Stack Overflow là thông tin chuyển đơn giản từ bộ điều khiển chế độ xem này sang bộ điều khiển chế độ xem tiếp theo.

Nếu chúng tôi đang sử dụng bảng phân cảnh, bộ điều khiển chế độ xem đầu tiên của chúng tôi có thể ghi đè prepareForSegue, đó chính xác là những gì nó ở đó. Một UIStoryboardSegueđối tượng được chuyển vào khi phương thức này được gọi và nó chứa một tham chiếu đến bộ điều khiển chế độ xem đích của chúng ta. Tại đây, chúng ta có thể đặt các giá trị mà chúng ta muốn chuyển.

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    if segue.identifier == "MySegueID" {
        if let destination = segue.destination as? SecondController {
            destination.myInformation = self.myInformation
        }
    }
}

Ngoài ra, nếu chúng ta không sử dụng bảng phân cảnh, thì chúng ta đang tải bộ điều khiển chế độ xem của mình từ một ngòi. Mã của chúng tôi sau đó đơn giản hơn một chút.

func showNextController() {
    let destination = SecondController(nibName: "SecondController", bundle: nil)
    destination.myInformation = self.myInformation
    show(destination, sender: self)
}

Trong cả hai trường hợp, myInformationlà một thuộc tính trên mỗi bộ điều khiển chế độ xem chứa bất kỳ dữ liệu nào cần được chuyển từ bộ điều khiển chế độ xem này sang bộ điều khiển chế độ xem tiếp theo. Chúng rõ ràng không cần phải có cùng tên trên mỗi bộ điều khiển.


Chúng tôi cũng có thể muốn chia sẻ thông tin giữa các tab trong a UITabBarController.

Trong trường hợp này, nó thực sự thậm chí còn đơn giản hơn.

Đầu tiên, hãy tạo một lớp con UITabBarControllervà cung cấp cho nó các thuộc tính cho bất kỳ thông tin nào chúng ta muốn chia sẻ giữa các tab khác nhau:

class MyCustomTabController: UITabBarController {
    var myInformation: [String: AnyObject]?
}

Bây giờ, nếu chúng tôi đang xây dựng ứng dụng của mình từ bảng phân cảnh, chúng tôi chỉ cần thay đổi lớp của bộ điều khiển thanh tab từ mặc định UITabBarControllerthành MyCustomTabController. Nếu chúng tôi không sử dụng bảng phân cảnh, chúng tôi chỉ cần khởi tạo một phiên bản của lớp tùy chỉnh này thay vì UITabBarControllerlớp mặc định và thêm bộ điều khiển chế độ xem của chúng tôi vào đây.

Bây giờ, tất cả các bộ điều khiển chế độ xem của chúng tôi trong bộ điều khiển thanh tab có thể truy cập thuộc tính này như:

if let tbc = self.tabBarController as? MyCustomTabController {
    // do something with tbc.myInformation
}

Và bằng cách phân lớp con UINavigationControllertheo cách tương tự, chúng ta có thể thực hiện cùng một cách tiếp cận để chia sẻ dữ liệu trên toàn bộ ngăn xếp điều hướng:

if let nc = self.navigationController as? MyCustomNavController {
    // do something with nc.myInformation
}

Có một số kịch bản khác. Không có nghĩa là câu trả lời này bao gồm tất cả chúng.


1
Tôi cũng muốn nói thêm rằng đôi khi bạn muốn một kênh gửi thông tin trở lại từ bộ điều khiển chế độ xem đích đến bộ điều khiển chế độ xem nguồn. Một cách phổ biến để xử lý tình huống đó là thêm thuộc tính ủy quyền vào đích, sau đó, trong phần chuẩn bị của bộ điều khiển chế độ xem nguồn, đặt thuộc tính ủy quyền của bộ điều khiển chế độ xem đích thành chính nó. (và xác định một giao thức định nghĩa các thông điệp đến đích VC sử dụng để gửi tin nhắn đến các nguồn VC)
Duncan C

1
nhgrif, tôi đồng ý. Lời khuyên cho các nhà phát triển mới là nếu bạn cần chuyển dữ liệu giữa các cảnh trên bảng phân cảnh, hãy sử dụng prepareForSegue. Thật tệ khi quan sát rất đơn giản này bị mất trong số các câu trả lời khác và lạc đề ở đây.
Rob

2
@Rob Yup. Singletons và thông báo nên là lựa chọn cuối cùng. Chúng ta nên thích prepareForSeguehoặc chuyển giao thông tin trực tiếp khác trong hầu hết mọi tình huống và sau đó đơn giản là ổn với người mới khi họ xuất hiện với tình huống mà những tình huống này không hoạt động và sau đó chúng ta phải dạy họ về những cách tiếp cận toàn cầu hơn này.
nhgrif

1
Nó phụ thuộc. Nhưng tôi rất, rất lo lắng về việc sử dụng app ủy quyền làm bãi chứa mã của chúng tôi mà chúng tôi không biết phải đặt ở đâu khác. Đây là con đường dẫn đến sự điên rồ.
nhgrif

2
@nhgrif. thx cho câu trả lời của bạn. Tuy nhiên, điều gì sẽ xảy ra nếu bạn muốn dữ liệu được chuyển giữa 4 hoặc 5 bộ điều khiển chế độ xem. nếu tôi có nói 4-5 bộ điều khiển chế độ xem quản lý đăng nhập và mật khẩu của máy khách, v.v. và tôi muốn chuyển email của người dùng giữa các bộ điều khiển chế độ xem này, có cách nào thuận tiện hơn để làm điều này hơn là khai báo var trong mỗi bộ điều khiển xem rồi chuyển nó vào trong readyforsegue. có cách nào tôi có thể khai báo một lần và mỗi bộ điều khiển chế độ xem có thể truy cập nó nhưng theo cách đó cũng là thực hành mã hóa tốt không?
lozflan

45

Câu hỏi này xuất hiện mọi lúc.

Một gợi ý là tạo singleton vùng chứa dữ liệu: Một đối tượng được tạo một lần và duy nhất một lần trong vòng đời ứng dụng của bạn và tồn tại trong suốt thời gian ứng dụng của bạn.

Cách tiếp cận này rất phù hợp cho tình huống khi bạn có dữ liệu ứng dụng toàn cầu cần có sẵn / có thể sửa đổi trên các lớp khác nhau trong ứng dụng của mình.

Các cách tiếp cận khác như thiết lập liên kết một chiều hoặc 2 chiều giữa các bộ điều khiển chế độ xem phù hợp hơn với các tình huống mà bạn đang chuyển trực tiếp thông tin / thông báo giữa các bộ điều khiển chế độ xem.

(Xem câu trả lời của nhgrif, bên dưới, để biết các lựa chọn thay thế khác.)

Với một singleton vùng chứa dữ liệu, bạn thêm một thuộc tính vào lớp của mình để lưu trữ một tham chiếu đến singleton của bạn, rồi sử dụng thuộc tính đó bất kỳ lúc nào bạn cần quyền truy cập.

Bạn có thể thiết lập singleton của mình để nó lưu nội dung của nó vào đĩa để trạng thái ứng dụng của bạn vẫn tồn tại giữa các lần khởi chạy.

Tôi đã tạo một dự án demo trên GitHub trình bày cách bạn có thể làm điều này. Đây là liên kết:

Dự án SwiftDataContainerSingleton trên GitHub Đây là README từ dự án đó:

SwiftDataContainerSingleton

Trình diễn việc sử dụng singleton vùng chứa dữ liệu để lưu trạng thái ứng dụng và chia sẻ nó giữa các đối tượng.

Các DataContainerSingletonlớp học là singleton thực tế.

Nó sử dụng một hằng số tĩnh sharedDataContainerđể lưu một tham chiếu đến singleton.

Để truy cập singleton, hãy sử dụng cú pháp

DataContainerSingleton.sharedDataContainer

Dự án mẫu xác định 3 thuộc tính trong vùng chứa dữ liệu:

  var someString: String?
  var someOtherString: String?
  var someInt: Int?

Để tải thuộc someInttính từ vùng chứa dữ liệu, bạn sẽ sử dụng mã như sau:

let theInt = DataContainerSingleton.sharedDataContainer.someInt

Để lưu một giá trị vào someInt, bạn sẽ sử dụng cú pháp:

DataContainerSingleton.sharedDataContainer.someInt = 3

initPhương thức của DataContainerSingleton thêm một trình quan sát cho UIApplicationDidEnterBackgroundNotification. Mã đó trông như thế này:

goToBackgroundObserver = NSNotificationCenter.defaultCenter().addObserverForName(
  UIApplicationDidEnterBackgroundNotification,
  object: nil,
  queue: nil)
  {
    (note: NSNotification!) -> Void in
    let defaults = NSUserDefaults.standardUserDefaults()
    //-----------------------------------------------------------------------------
    //This code saves the singleton's properties to NSUserDefaults.
    //edit this code to save your custom properties
    defaults.setObject( self.someString, forKey: DefaultsKeys.someString)
    defaults.setObject( self.someOtherString, forKey: DefaultsKeys.someOtherString)
    defaults.setObject( self.someInt, forKey: DefaultsKeys.someInt)
    //-----------------------------------------------------------------------------

    //Tell NSUserDefaults to save to disk now.
    defaults.synchronize()
}

Trong mã quan sát, nó lưu các thuộc tính của vùng chứa dữ liệu vào NSUserDefaults. Bạn cũng có thể sử dụng NSCoding, Dữ liệu cốt lõi hoặc nhiều phương pháp khác để lưu dữ liệu trạng thái.

initPhương thức của DataContainerSingleton cũng cố gắng tải các giá trị đã lưu cho các thuộc tính của nó.

Phần đó của phương thức init trông giống như sau:

let defaults = NSUserDefaults.standardUserDefaults()
//-----------------------------------------------------------------------------
//This code reads the singleton's properties from NSUserDefaults.
//edit this code to load your custom properties
someString = defaults.objectForKey(DefaultsKeys.someString) as! String?
someOtherString = defaults.objectForKey(DefaultsKeys.someOtherString) as! String?
someInt = defaults.objectForKey(DefaultsKeys.someInt) as! Int?
//-----------------------------------------------------------------------------

Các khóa để tải và lưu giá trị vào NSUserDefaults được lưu trữ dưới dạng hằng số chuỗi là một phần của cấu trúc DefaultsKeys, được định nghĩa như sau:

struct DefaultsKeys
{
  static let someString  = "someString"
  static let someOtherString  = "someOtherString"
  static let someInt  = "someInt"
}

Bạn tham chiếu một trong những hằng số như thế này:

DefaultsKeys.someInt

Sử dụng singleton vùng chứa dữ liệu:

Ứng dụng mẫu này sử dụng trival singleton vùng chứa dữ liệu.

Có hai bộ điều khiển chế độ xem. Đầu tiên là lớp con tùy chỉnh của UIViewController ViewControllervà lớp thứ hai là lớp con tùy chỉnh của UIViewController SecondVC.

Cả hai bộ điều khiển chế độ xem đều có trường văn bản trên chúng và cả hai đều tải một giá trị từ thuộc tính singlelton của vùng chứa dữ liệu someIntvào trường văn bản trongviewWillAppear phương thức và cả hai đều lưu giá trị hiện tại từ trường văn bản trở lại `someInt 'của vùng chứa dữ liệu.

Mã để tải giá trị vào trường văn bản nằm trong viewWillAppear:phương thức:

override func viewWillAppear(animated: Bool)
{
  //Load the value "someInt" from our shared ata container singleton
  let value = DataContainerSingleton.sharedDataContainer.someInt ?? 0
  
  //Install the value into the text field.
  textField.text =  "\(value)"
}

Mã để lưu giá trị do người dùng chỉnh sửa trở lại vùng chứa dữ liệu nằm trong textFieldShouldEndEditingphương thức của bộ điều khiển chế độ xem :

 func textFieldShouldEndEditing(textField: UITextField) -> Bool
 {
   //Save the changed value back to our data container singleton
   DataContainerSingleton.sharedDataContainer.someInt = textField.text!.toInt()
   return true
 }

Bạn nên tải các giá trị vào giao diện người dùng của mình trong viewWillAppear thay vì viewDidLoad để giao diện người dùng của bạn cập nhật mỗi khi bộ điều khiển chế độ xem được hiển thị.


8
Tôi không muốn bỏ phiếu vì tôi nghĩ thật tuyệt khi bạn đã đầu tư thời gian để tạo câu hỏi và câu trả lời như một nguồn tài liệu. Cảm ơn bạn. Mặc dù vậy, tôi nghĩ rằng chúng tôi có lợi ích lớn đối với các nhà phát triển mới để ủng hộ các singlelet cho các đối tượng mô hình. Tôi không ở trong trại "singletons is evil" (mặc dù noobs nên google cụm từ đó để đánh giá tốt hơn các vấn đề), nhưng tôi nghĩ rằng dữ liệu mô hình là một cách sử dụng singleton đáng nghi vấn / gây tranh cãi.
Rob

rất thích nhìn thấy một bài viết tuyệt vời như của bạn về các liên kết 2 chiều
Cmag 19:16

@Duncan C Xin chào Duncan Tôi đang tạo đối tượng tĩnh trong mỗi mô hình nên tôi lấy Dữ liệu từ bất kỳ nơi nào đó là cách tiếp cận phù hợp hoặc tôi phải làm theo con đường của bạn vì Nó có vẻ rất đúng.
Virendra Singh Rathore,

@VirendraSinghRathore, Biến tĩnh toàn cục là cách tồi tệ nhất có thể để chia sẻ dữ liệu trên ứng dụng. Họ kết hợp chặt chẽ các phần của ứng dụng của bạn với nhau và giới thiệu sự phụ thuộc lẫn nhau nghiêm trọng. Nó hoàn toàn ngược lại với "rất đúng".
Duncan C

@DuncanC - mẫu này có hoạt động với đối tượng CurrentUser không - về cơ bản là một người dùng đã đăng nhập vào ứng dụng của bạn? thx
timpone

9

Swift 4

Có rất nhiều cách tiếp cận để truyền dữ liệu nhanh chóng. Ở đây tôi đang thêm một số cách tiếp cận tốt nhất của nó.

1) Sử dụng StoryBoard Segue

Các phân đoạn của bảng phân cảnh rất hữu ích cho việc truyền dữ liệu giữa các Bộ điều khiển Chế độ xem Nguồn và Đích và ngược lại.

// If you want to pass data from ViewControllerB to ViewControllerA while user tap on back button of ViewControllerB.
        @IBAction func unWindSeague (_ sender : UIStoryboardSegue) {
            if sender.source is ViewControllerB  {
                if let _ = sender.source as? ViewControllerB {
                    self.textLabel.text = "Came from B = B->A , B exited"
                }
            }
        }

// If you want to send data from ViewControllerA to ViewControllerB
        override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
            if  segue.destination is ViewControllerB {
                if let vc = segue.destination as? ViewControllerB {
                    vc.dataStr = "Comming from A View Controller"
                }
            }
        }

2) Sử dụng phương pháp ủy quyền

ViewControllerD

//Make the Delegate protocol in Child View Controller (Make the protocol in Class from You want to Send Data)
    protocol  SendDataFromDelegate {
        func sendData(data : String)
    }

    import UIKit

    class ViewControllerD: UIViewController {

        @IBOutlet weak var textLabelD: UILabel!

        var delegate : SendDataFromDelegate?  //Create Delegate Variable for Registering it to pass the data

        override func viewDidLoad() {
            super.viewDidLoad()
            // Do any additional setup after loading the view.
            textLabelD.text = "Child View Controller"
        }

        @IBAction func btnDismissTapped (_ sender : UIButton) {
            textLabelD.text = "Data Sent Successfully to View Controller C using Delegate Approach"
            self.delegate?.sendData(data:textLabelD.text! )
            _ = self.dismiss(animated: true, completion:nil)
        }
    }

ViewControllerC

    import UIKit

    class ViewControllerC: UIViewController , SendDataFromDelegate {

        @IBOutlet weak var textLabelC: UILabel!

        override func viewDidLoad() {
            super.viewDidLoad()
            // Do any additional setup after loading the view.
        }

        @IBAction func btnPushToViewControllerDTapped( _ sender : UIButton) {
            if let vcD = self.storyboard?.instantiateViewController(withIdentifier: "ViewControllerD") as?  ViewControllerD  {
                vcD.delegate = self // Registring Delegate (When View Conteoller D gets Dismiss It can call sendData method
    //            vcD.textLabelD.text = "This is Data Passing by Referenceing View Controller D Text Label." //Data Passing Between View Controllers using Data Passing
                self.present(vcD, animated: true, completion: nil)
            }
        }

        //This Method will called when when viewcontrollerD will dismiss. (You can also say it is a implementation of Protocol Method)
        func sendData(data: String) {
            self.textLabelC.text = data
        }

    }

Đối với các nhân viên Google, những người hoàn toàn không biết phải đặt các đoạn mã Swift của StackOverflow ở đâu, vì có vẻ như bạn nên luôn biết họ suy ra mã ở đâu: Tôi đã sử dụng Tùy chọn 1) để gửi từ ViewControllerAđến ViewControllerB. Tôi chỉ dán đoạn mã ở cuối của tôi ViewControllerA.swift(tất nhiên ViewControllerA.swiftlà nơi thực sự là bất cứ thứ gì tệp của bạn được đặt tên) ngay trước dấu ngoặc nhọn cuối cùng. " prepare" thực sự là một hàm đặc biệt được tích hợp sẵn từ trước trong một Lớp nhất định [không có tác dụng gì], đó là lý do tại sao bạn phải " override" nó
velkoon

8

Một giải pháp thay thế khác là sử dụng trung tâm thông báo (NSNotificationCenter) và đăng thông báo. Đó là một khớp nối rất lỏng lẻo. Người gửi thông báo không cần biết hoặc quan tâm xem ai đang nghe. Nó chỉ đăng một thông báo và quên nó đi.

Thông báo rất tốt cho việc truyền một đến nhiều thông báo, vì có thể có một số lượng người quan sát tùy ý lắng nghe một thông báo nhất định.


2
Lưu ý rằng việc sử dụng trung tâm thông báo giới thiệu khớp nối có lẽ quá lỏng lẻo. Nó có thể làm cho việc truy tìm dòng chảy của chương trình của bạn trở nên rất khó khăn, vì vậy nó nên được sử dụng cẩn thận.
Duncan C

2

Thay vì tạo một singelton bộ điều khiển dữ liệu, tôi khuyên bạn nên tạo một cá thể bộ điều khiển dữ liệu và chuyển nó xung quanh. Để hỗ trợ tiêm phụ thuộc, trước tiên tôi sẽ tạo một DataControllergiao thức:

protocol DataController {
    var someInt : Int {get set} 
    var someString : String {get set}
}

Sau đó, tôi sẽ tạo một SpecificDataController (hoặc bất kỳ tên nào hiện tại sẽ phù hợp):

class SpecificDataController : DataController {
   var someInt : Int = 5
   var someString : String = "Hello data" 
}

Sau đó, ViewControllerlớp sẽ có một trường để chứa dataController. Lưu ý rằng loại của dataControllerlà giao thứcDataController . Bằng cách này, thật dễ dàng để chuyển đổi việc triển khai bộ điều khiển dữ liệu:

class ViewController : UIViewController {
   var dataController : DataController?
   ...
}

Trong AppDelegatechúng ta có thể thiết lập viewController'sdataController :

 func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
    if let viewController = self.window?.rootViewController as? ViewController {
        viewController.dataController =  SpecificDataController()
    }   
    return true
}

Khi chúng ta chuyển sang một viewController khác, chúng ta có thể chuyển dataController sang:

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
    ...   
}

Bây giờ khi chúng ta muốn chuyển bộ điều khiển dữ liệu cho một tác vụ khác, chúng ta có thể thực hiện việc này trong AppDelegate và không phải thay đổi bất kỳ mã nào khác sử dụng bộ điều khiển dữ liệu.

Tất nhiên điều này là quá mức cần thiết nếu chúng ta chỉ muốn chuyển xung quanh một giá trị duy nhất. Trong trường hợp này, tốt nhất bạn nên chọn câu trả lời của nhgrif.

Với cách tiếp cận này, chúng ta có thể tách hình thức xem thành phần logic.


1
Xin chào, cách tiếp cận này là sạch, có thể kiểm tra và những gì tôi sử dụng hầu hết thời gian trong các ứng dụng nhỏ, nhưng trong những ứng dụng lớn hơn, nơi không phải mọi VC (có lẽ thậm chí không phải VC gốc) đều có thể cần sự phụ thuộc (ví dụ: DataController trong trường hợp này) nó dường như lãng phí cho mọi VC yêu cầu sự phụ thuộc chỉ để vượt qua nó. Ngoài ra, nếu bạn sử dụng các loại VC khác nhau (ví dụ: UIVC thông thường so với NavigationVC) thì bạn cần phải phân lớp các loại khác nhau đó chỉ để thêm biến phụ thuộc đó. Làm thế nào để bạn tiếp cận điều này?
RobertoCuba

1

Như @nhgrif đã chỉ ra trong câu trả lời xuất sắc của mình, có rất nhiều cách khác nhau mà VC (bộ điều khiển chế độ xem) và các đối tượng khác có thể giao tiếp với nhau.

Dữ liệu đơn lẻ mà tôi đã nêu trong câu trả lời đầu tiên của mình thực sự thiên về chia sẻ và lưu trạng thái toàn cầu hơn là về giao tiếp trực tiếp.

câu trả lời của nhrif cho phép bạn gửi thông tin trực tiếp từ nguồn đến VC đích. Như tôi đã đề cập trong phần trả lời, cũng có thể gửi tin nhắn trở lại từ đích đến nguồn.

Trên thực tế, bạn có thể thiết lập kênh một chiều hoặc 2 chiều hoạt động giữa các bộ điều khiển chế độ xem khác nhau. Nếu các bộ điều khiển chế độ xem được liên kết thông qua một phân cảnh bảng phân cảnh, thì thời gian để thiết lập các liên kết là trong phương thức Chuẩn bị cho phân cảnh.

Tôi có một dự án mẫu trên Github sử dụng bộ điều khiển chế độ xem cha để lưu trữ 2 chế độ xem bảng khác nhau khi còn nhỏ. Các bộ điều khiển chế độ xem con được liên kết bằng cách sử dụng các segues nhúng và bộ điều khiển chế độ xem mẹ kết nối các liên kết 2 chiều với mỗi bộ điều khiển chế độ xem trong phương thức chuẩn bị.

Bạn có thể tìm thấy dự án đó trên github (liên kết). Tuy nhiên, tôi đã viết nó bằng Objective-C và chưa chuyển nó sang Swift, vì vậy nếu bạn không thích Objective-C thì có thể hơi khó theo dõi


1

SWIFT 3:

Nếu bạn có một bảng phân cảnh với việc sử dụng các segues đã xác định:

func prepare(for segue: UIStoryboardSegue, sender: Any?)

Mặc dù nếu bạn làm mọi thứ theo lập trình bao gồm điều hướng giữa các UIViewControllers khác nhau thì hãy sử dụng phương pháp:

func navigationController(_ navigationController: UINavigationController, willShow viewController: UIViewController, animated: Bool)

Lưu ý: để sử dụng theo cách thứ hai, bạn cần tạo UINavigationController của mình, bạn đang đẩy UIViewControllers vào, một đại biểu và nó cần tuân theo giao thức UINavigationControllerDelegate:

   class MyNavigationController: UINavigationController, UINavigationControllerDelegate {

    override func viewDidLoad() {
        self.delegate = self
    }

    func navigationController(_ navigationController: UINavigationController, willShow viewController: UIViewController, animated: Bool) {

     // do what ever you need before going to the next UIViewController or back
     //this method will be always called when you are pushing or popping the ViewController

    }
}

never do self.delegate = self
malhal

1

Nó phụ thuộc vào thời điểm bạn muốn lấy dữ liệu.

Nếu bạn muốn lấy dữ liệu bất cứ khi nào bạn muốn, có thể sử dụng một mẫu singleton. Lớp mẫu hoạt động trong thời gian chạy ứng dụng. Đây là một ví dụ về mô hình singleton.

class AppSession: NSObject {

    static let shared = SessionManager()
    var username = "Duncan"
}

class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()

        print(AppSession.shared.username)
    }
}

Nếu bạn muốn lấy dữ liệu sau bất kỳ hành động nào, có thể sử dụng NotificationCenter.

extension Notification.Name {
    static let loggedOut = Notification.Name("loggedOut")
}

@IBAction func logoutAction(_ sender: Any) {
    NotificationCenter.default.post(name: .loggedOut, object: nil)
}

NotificationCenter.default.addObserver(forName: .loggedOut, object: nil, queue: OperationQueue.main) { (notify) in
    print("User logged out")
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.