我是 iOS 和 Objective-C 以及整个 的新手MVC 范例,我坚持以下几点:
我有一个充当数据输入表单的视图,我想为用户提供选择多个产品的选项。产品使用 UITableViewController
列在另一个视图上,并且我启用了多个选择。
如何将数据从一个视图传输到另一个视图?我将把 UITableView
上的选择保存在一个数组中,但是如何将其传递回之前的数据输入表单视图,以便在提交时将其与其他数据一起保存到 Core Data形式?
我四处浏览,看到有些人在应用程序委托中声明了一个数组。我读了一些关于 singletons 的内容,但我不明白这些是什么,我读了一些关于创建的内容数据模型。
执行此操作的正确方法是什么?我将如何进行?
I'm new to iOS and Objective-C and the whole MVC paradigm and I'm stuck with the following:
I have a view that acts as a data entry form and I want to give the user the option to select multiple products. The products are listed on another view with a UITableViewController
and I have enabled multiple selections.
How do I transfer the data from one view to another? I will be holding the selections on the UITableView
in an array, but how do I then pass that back to the previous data entry form view so it can be saved along with the other data to Core Data on submission of the form?
I have surfed around and seen some people declare an array in the app delegate. I read something about singletons, but I don't understand what these are and I read something about creating a data model.
What would be the correct way of performing this and how would I go about it?
发布评论
评论(30)
NewsViewController
NewsDetailViewController.h
NewsDetailViewController.m
NewsViewController
NewsDetailViewController.h
NewsDetailViewController.m
当您使用 .xib 文件时,委派是执行此类操作的唯一一种解决方案。但是,之前的所有答案都是针对 .xibs 文件的
storyboard
。您需要使用委托。这是您可以使用的唯一解决方案。另一个解决方案是使用单例类模式。初始化一次并在整个应用程序中使用它。
Delegation is the only one solution to perform such operations when you are using .xib files. However, all previous answers are for
storyboard
for .xibs files. You need to use delegation. That's the only solution you can use.Another solution is use the singleton class pattern. Initialize it once and use it in your entire app.
对于 SwiftUI
将
@EnvironmentObject
视为在大量视图上使用@ObservedObject
的更智能、更简单的方法。您可以在视图 A 中创建一些数据,然后将其传递给视图 B,然后传递给视图 C,然后传递给视图 D,然后最后使用它,而不是在视图 A 中创建一些数据,然后将其传递给视图 B、视图 C、视图 D,然后再最终使用它,您可以在视图中创建数据并将其放入环境中,以便视图 B、C 和 D自动有权访问它。注意:环境对象必须由祖先视图提供 - 如果 SwiftUI 找不到正确类型的环境对象,您将会崩溃。这也适用于预览,所以要小心。
例如,这是一个存储用户设置的可观察对象:
For SwiftUI
Think of
@EnvironmentObject
as a smarter, simpler way of using@ObservedObject
on lots of views. Rather than creating some data in view A, then passing it to view B, then view C, then view D before finally using it, you can create it in view and put it into the environment so that views B, C, and D will automatically have access to it.Note: Environment objects must be supplied by an ancestor view – if SwiftUI can’t find an environment object of the correct type you’ll get a crash. This applies for previews too, so be careful.
As an example, here’s an observable object that stores user settings:
此处演示项目链接 - https:// github.com/kamanijasmin13/Swift-Pass-data- Between-viewcontrollers
以编程方式
继续
用户默认值
演示项目链接在这里 - https://github.com/kamanijasmin13/Swift-Pass-data- Between-viewcontrollers
Demo Project Link Here - https://github.com/kamanijasmin13/Swift-Pass-data-between-viewcontrollers
Programatically
Segue
UserDefaults
Demo Project Link Here - https://github.com/kamanijasmin13/Swift-Pass-data-between-viewcontrollers
我喜欢基于 NSProxy 的模型对象和模拟对象的想法,以便在用户选择可以取消的情况下提交或丢弃数据。
传递数据很容易,因为它是单个对象或几个对象,如果您有一个 UINavigationController 控制器,您可以将对模型的引用保留在内部,并且所有推送的视图控制器都可以直接从导航控制器访问它。
I like the idea of model objects and mock objects based on NSProxy to commit or discard data if what the user selects can be cancelled.
It's easy to pass data around since it's a single object or couple of objects and if you have, let's say, a UINavigationController controller, you can keep the reference to the model inside and all pushed view controllers can access it directly from the navigation controller.
我见过很多人使用
didSelectRowAtPath
方法使这个过程变得复杂。我在示例中使用 核心数据。方法内四行代码就完成了。
I have seen a lot of people over complicating this using the
didSelectRowAtPath
method. I am using Core Data in my example.Four lines of code inside the method and you are done.
这个问题在 StackOverflow 上似乎很受欢迎,所以我想我会尝试给出一个更好的答案来帮助像我一样刚开始接触 iOS 世界的人。
转发数据
将数据从另一个视图控制器转发到另一个视图控制器。如果您想将对象/值从一个视图控制器传递到另一个可能推送到导航堆栈的视图控制器,则可以使用此方法。
对于此示例,我们将使用
ViewControllerA
和ViewControllerB
将
BOOL
值从ViewControllerA
传递到ViewControllerB
我们将执行以下操作。在
ViewControllerB.h
中为BOOL
创建一个属性在
ViewControllerA
中,您需要告诉它有关ViewControllerB
的信息所以使用<前><代码>#import“ViewControllerB.h”
在要加载视图的位置使用 Then,例如
didSelectRowAtIndex
或某些IBAction
,在将其推送到导航堆栈之前,您需要在ViewControllerB
中设置该属性。这会将
ViewControllerB
中的isSomethingEnabled
设置为BOOL
值YES
。使用 Segue 转发数据
如果您使用 Storyboard,则很可能会使用 Segue,并且需要此过程来转发数据。这与上面类似,但不是在推送视图控制器之前传递数据,而是使用名为
So 的方法将
BOOL
从ViewControllerA
传递到ViewControllerB
我们将执行以下操作:在
ViewControllerB.h
中为BOOL
创建一个属性在
ViewControllerA
中,您需要告诉它有关ViewControllerB
的信息,所以使用<前><代码>#import“ViewControllerB.h”
创建从
ViewControllerA
到ViewControllerB
的转场> 在故事板上并为其指定一个标识符。在此示例中,我们将其称为“showDetailSegue”
接下来,我们需要将方法添加到执行任何 segue 时调用的
ViewControllerA
中。因此,我们需要检测调用了哪个 segue,然后执行某些操作。在我们的示例中,我们将检查"showDetailSegue"
,如果执行了,我们会将BOOL
值传递给ViewControllerB
如果您有自己的观点嵌入导航控制器中,您需要将上面的方法稍微更改为以下内容
这会将
ViewControllerB
中的isSomethingEnabled
设置为BOOL
值是的。
传回数据
要将数据从
ViewControllerB
传回ViewControllerA
,您需要使用协议和委托或块,后者可以用作回调的松耦合机制。为此,我们将使
ViewControllerA
成为ViewControllerB
的委托。这允许 ViewControllerB 向ViewControllerA 发送消息,使我们能够发送数据。
要使
ViewControllerA
成为ViewControllerB
的委托,它必须符合我们必须指定的ViewControllerB
协议。这告诉 ViewControllerA 它必须实现哪些方法。在
ViewControllerB.h
中,在#import
下方、@interface
上方指定协议。接下来还是在
ViewControllerB.h
中,您需要设置一个delegate
属性并在ViewControllerB.m
中综合在
ViewControllerB
当我们弹出视图控制器时,我们在委托
上调用一条消息。这就是
ViewControllerB
。现在,在ViewControllerA.h
中,告诉ViewControllerA
导入ViewControllerB
并遵守其协议。<前><代码>#import“ViewControllerB.h”
@interface ViewControllerA : UIViewController;
在
ViewControllerA.m
中实现我们协议中的以下方法在将
viewControllerB
推送到导航堆栈之前,我们需要告诉ViewControllerB
ViewControllerA
是它的委托,否则我们会得到一个错误。参考文献
NSNotification center
这是传递数据的另一种方式。
将数据从一个类传递回另一个类(类可以是任何控制器、网络/会话管理器、UIView 子类或任何其他类)
块是匿名函数。
此示例传递数据从控制器B到控制器A
定义块
添加块处理程序(侦听器)
在您需要值的地方(例如,您需要 ControllerA 中的 API 响应,或者需要 A 上的 ContorllerB 数据)
转到控制器 B
Fire block
块的另一个工作示例
This question seems to be very popular here on Stack Overflow so I thought I would try and give a better answer to help out people starting in the world of iOS like me.
Passing Data Forward
Passing data forward to a view controller from another view controller. You would use this method if you wanted to pass an object/value from one view controller to another view controller that you may be pushing on to a navigation stack.
For this example, we will have
ViewControllerA
andViewControllerB
To pass a
BOOL
value fromViewControllerA
toViewControllerB
we would do the following.in
ViewControllerB.h
create a property for theBOOL
in
ViewControllerA
you need to tell it aboutViewControllerB
so use anThen where you want to load the view, for example,
didSelectRowAtIndex
or someIBAction
, you need to set the property inViewControllerB
before you push it onto the navigation stack.This will set
isSomethingEnabled
inViewControllerB
toBOOL
valueYES
.Passing Data Forward using Segues
If you are using Storyboards you are most likely using segues and will need this procedure to pass data forward. This is similar to the above but instead of passing the data before you push the view controller, you use a method called
So to pass a
BOOL
fromViewControllerA
toViewControllerB
we would do the following:in
ViewControllerB.h
create a property for theBOOL
in
ViewControllerA
you need to tell it aboutViewControllerB
, so use anCreate the segue from
ViewControllerA
toViewControllerB
on the storyboard and give it an identifier. In this example we'll call it"showDetailSegue"
Next, we need to add the method to
ViewControllerA
that is called when any segue is performed. Because of this we need to detect which segue was called and then do something. In our example, we will check for"showDetailSegue"
and if that's performed, we will pass ourBOOL
value toViewControllerB
If you have your views embedded in a navigation controller, you need to change the method above slightly to the following
This will set
isSomethingEnabled
inViewControllerB
toBOOL
valueYES
.Passing Data Back
To pass data back from
ViewControllerB
toViewControllerA
you need to use Protocols and Delegates or Blocks, the latter can be used as a loosely coupled mechanism for callbacks.To do this we will make
ViewControllerA
a delegate ofViewControllerB
. This allowsViewControllerB
to send a message back toViewControllerA
enabling us to send data back.For
ViewControllerA
to be a delegate ofViewControllerB
it must conform toViewControllerB
's protocol which we have to specify. This tellsViewControllerA
which methods it must implement.In
ViewControllerB.h
, below the#import
, but above@interface
you specify the protocol.Next still in the
ViewControllerB.h
, you need to set up adelegate
property and synthesize inViewControllerB.m
In
ViewControllerB
we call a message on thedelegate
when we pop the view controller.That's it for
ViewControllerB
. Now inViewControllerA.h
, tellViewControllerA
to importViewControllerB
and conform to its protocol.In
ViewControllerA.m
implement the following method from our protocolBefore pushing
viewControllerB
to navigation stack we need to tellViewControllerB
thatViewControllerA
is its delegate, otherwise we will get an error.References
NSNotification center
It's another way to pass data.
Passing Data back from one class to another (A class can be any controller, Network/session manager, UIView subclass or any other class)
Blocks are anonymous functions.
This example passes data from Controller B to Controller A
Define a block
Add block handler (listener)
Where you need a value (for example, you need your API response in ControllerA or you need ContorllerB data on A)
Go to Controller B
Fire block
Another Working Example for Blocks
Swift
这里和 StackOverflow 周围有大量的解释,但如果你是一个初学者,只是想尝试一些基本的工作,请尝试观看这个 YouTube 教程(它帮助我最终理解了如何做到这一点)。
将数据转发到下一个视图控制器
以下是基于视频的示例。这个想法是将字符串从第一个视图控制器中的文本字段传递到第二个视图控制器中的标签。
在 Interface Builder 中创建故事板布局。要进行转场,您只需 Control 单击按钮并拖动到第二个视图控制器。
第一个视图控制器
第一个视图控制器的代码是
第二个视图控制器
,第二个视图控制器的代码是
不要忘记
UITextField
和UILabel
的出口。将数据传递回前一个视图控制器
要将数据从第二个视图控制器传递回第一个视图控制器,您可以使用协议和委托。该视频非常清晰地介绍了该过程:
以下是基于视频的示例(经过一些修改)。
在 Interface Builder 中创建故事板布局。同样,要进行转场,您只需 Control 从按钮拖动到第二个视图控制器。将 Segue 标识符设置为
showSecondViewController
。另外,不要忘记使用以下代码中的名称连接插座和操作。第一个视图控制器
第一个视图控制器的代码
请注意我们自定义的
DataEnteredDelegate
协议的使用。第二个视图控制器和协议
第二个视图控制器的代码是
请注意,
协议
位于视图控制器类之外。就是这样。现在运行应用程序,您应该能够将数据从第二个视图控制器发送回第一个视图控制器。
Swift
There are tons and tons of explanations here and around Stack Overflow, but if you are a beginner just trying to get something basic to work, try watching this YouTube tutorial (It's what helped me to finally understand how to do it).
Passing data forward to the next View Controller
The following is an example based on the video. The idea is to pass a string from the text field in the First View Controller to the label in the Second View Controller.
Create the storyboard layout in the Interface Builder. To make the segue, you just Control click on the button and drag over to the Second View Controller.
First View Controller
The code for the First View Controller is
Second View Controller
And the code for the Second View Controller is
Don't forget
UITextField
and theUILabel
.Passing data back to the previous View Controller
To pass data back from the second view controller to the first view controller, you use a protocol and a delegate. This video is a very clear walk though of that process:
The following is an example based on the video (with a few modifications).
Create the storyboard layout in the Interface Builder. Again, to make the segue, you just Control drag from the button to the Second View Controller. Set the segue identifier to
showSecondViewController
. Also, don't forget to hook up the outlets and actions using the names in the following code.First View Controller
The code for the First View Controller is
Note the use of our custom
DataEnteredDelegate
protocol.Second View Controller and Protocol
The code for the second view controller is
Note that the
protocol
is outside of the View Controller class.That's it. Running the app now, you should be able to send data back from the second view controller to the first.
MVC 中的 M 代表“模型”,在 MVC 范例中,模型类的作用是管理程序的数据。模型与视图相反——视图知道如何显示数据,但它不知道如何处理数据,而模型知道如何处理数据的一切,但不知道如何显示数据。模型可以很复杂,但不一定如此——您的应用程序的模型可能像字符串或字典数组一样简单。
控制器的作用是在视图和模型之间进行调解。因此,它们需要对一个或多个视图对象和一个或多个模型对象的引用。假设您的模型是一个字典数组,每个字典代表表中的一行。应用程序的根视图显示该表,并且它可能负责从文件加载数组。当用户决定向表中添加新行时,他们点击某个按钮,您的控制器会创建一个新的(可变)字典并将其添加到数组中。为了填充该行,控制器创建一个详细视图控制器并为其提供新的字典。详细视图控制器填充字典并返回。字典已经是模型的一部分,所以不需要发生任何其他事情。
The M in MVC is for "Model" and in the MVC paradigm the role of model classes is to manage a program's data. A model is the opposite of a view -- a view knows how to display data, but it knows nothing about what to do with data, whereas a model knows everything about how to work with data, but nothing about how to display it. Models can be complicated, but they don't have to be -- the model for your app might be as simple as an array of strings or dictionaries.
The role of a controller is to mediate between view and model. Therefore, they need a reference to one or more view objects and one or more model objects. Let's say that your model is an array of dictionaries, with each dictionary representing one row in your table. The root view for your app displays that table, and it might be responsible for loading the array from a file. When the user decides to add a new row to the table, they tap some button and your controller creates a new (mutable) dictionary and adds it to the array. In order to fill in the row, the controller creates a detail view controller and gives it the new dictionary. The detail view controller fills in the dictionary and returns. The dictionary is already part of the model, so nothing else needs to happen.
iOS 中不同类可以通过多种方式接收数据。例如 -
NSUserDefaults
中 - 用于稍后访问但是对于将值传递给另一个类(其分配在当前类中完成)的简单场景,最常见和首选的方法是分配后直接设置值。其完成方式如下:
我们可以使用两个控制器来理解它 - Controller1 和 Controller2
假设在 Controller1 类中您要创建 Controller2 对象并通过传递的 String 值推送它。可以这样做:
在Controller2类的实现中会有这个函数:
您也可以直接设置Controller2类的属性,方法类似:
要传递多个值,可以使用多个参数例如:
或者,如果您需要传递三个以上与公共功能相关的参数,您可以将这些值存储在模型类中,并将该 modelObject 传递给下一个类。
简而言之,如果您想 -
There are various ways by which data can be received by a different class in iOS. For example -
NSUserDefaults
- for accessing it laterBut for the simple scenario of passing a value to a different class whose allocation is done in the current class, the most common and preferred method would be the direct setting of values after allocation. This is done as follows:
We can understand it using two controllers - Controller1 and Controller2
Suppose in Controller1 class you want to create the Controller2 object and push it with a String value being passed. This can be done as this:
In the implementation of the Controller2 class there will be this function as:
You can also directly set the properties of the Controller2 class in the similar way as this:
To pass multiple values, you can use the multiple parameters like:
Or if you need to pass more than three parameters which are related to a common feature, you can store the values in a model class and pass that modelObject to the next class
So in short, if you want to -
经过更多研究后,似乎协议和委托是正确的/Apple首选的执行此操作的方式。
我最终使用了这个例子(在iPhone开发SDK中):
在视图控制器和其他对象之间共享数据
它工作得很好,允许我在视图之间前后传递字符串和数组。
After more research it seemed that protocols and delegates were the correct/Apple preferred way of doing this.
I ended up using this example (in the iPhone development SDK):
Sharing data between view controllers and other objects
It worked fine and allowed me to pass a string and an array forward and back between my views.
我发现最简单、最优雅的版本带有传递块。
我们将等待返回数据的视图控制器命名为“A”,将返回视图控制器命名为“B”。在此示例中,我们想要获取 2 个值:第一个值是 Type1,第二个值是 Type2。
假设我们使用 Storyboard,第一个控制器设置回调块,例如在 segue 准备期间:
并且“B”视图控制器应该声明回调属性,BViewController.h:
比在实现文件 BViewController.m 中我们获得返回回调所需的值后应该是调用:
要记住的一件事是,使用块通常需要管理强引用和__弱引用,如解释的此处
I find simplest and most elegant version with passing blocks.
Let's name view controller that waits for returned data as "A" and returning view controller as "B". In this example we want to get 2 values: first of Type1 and second of Type2.
Assuming we use Storyboard, first controller sets callback block, for example during segue preparation:
and "B" view controller should declare callback property, BViewController.h:
Than in implementation file BViewController.m after we have desired values to return our callback should be called:
One thing to remember is that using block often needs to manage strong and __weak references like explained here
许多答案都提供了一些很好的信息,但没有一个完全解决问题。
该问题询问有关在视图控制器之间传递信息的问题。给出的具体示例询问在视图之间传递信息,但考虑到 iOS 的自我声明的新颖性,原始发布者可能意味着在视图控制器之间,而不是在视图之间(没有视图控制器的任何参与)。似乎所有的答案都集中在两个视图控制器上,但是如果应用程序发展到需要在信息交换中涉及两个以上的视图控制器怎么办?
原发帖者还询问了Singletons和AppDelegate的使用。这些问题需要得到解答。
为了帮助其他人看到这个问题并想要完整的答案,我将尝试提供它。
应用场景
与其进行高度假设的抽象讨论,不如考虑具体的应用程序。为了帮助定义两个视图控制器的情况和两个以上视图控制器的情况,我将定义两个具体的应用场景。
场景一:最多有两个视图控制器需要共享信息。
见图一。
应用程序中有两个视图控制器。有一个ViewControllerA(数据输入表单)和ViewControllerB(产品列表)。产品列表中选择的项目必须与数据输入表单中文本框中显示的项目相匹配。在这种情况下,ViewControllerA 和 ViewControllerB 必须直接相互通信,而不能与其他视图控制器通信。
场景二:两个以上的视图控制器需要共享相同的信息。
见图二。
应用程序中有四个视图控制器。它是一个基于选项卡的应用程序,用于管理家庭库存。三个视图控制器呈现相同数据的不同过滤视图:
任何时候创建或编辑单个物品时,它也必须与其他物品同步视图控制器。例如,如果我们在 ViewControllerD 中添加一艘船,但尚未投保,那么当用户前往 ViewControllerA(奢侈品)和 ViewControllerC(整个家居库存)时,该船一定会出现,但当用户前往ViewControllerB(非保险物品)。我们不仅需要关注添加新项目,还需要关注删除项目(这可能从四个视图控制器中的任何一个允许),或编辑现有项目(这可能从“添加新项目表单”允许,重新利用相同的项目)用于编辑)。
由于所有视图控制器确实需要共享相同的数据,因此所有四个视图控制器都需要保持同步,因此每当任何单个视图控制器更改底层数据时,都需要与所有其他视图控制器进行某种通信。很明显,我们不希望在这种情况下每个视图控制器直接与其他视图控制器通信。如果不明显,请考虑我们是否有 20 个不同的视图控制器(而不仅仅是 4 个)。每当一个视图控制器做出更改时,通知其他 19 个视图控制器有多困难且容易出错?
解决方案:委托、观察者模式和单例
一中,我们有几个可行的解决方案,因为其他答案已经给出了
在场景 第二,我们还有其他可行的解决方案:
单例 是类的一个实例,该实例是其生命周期中唯一存在的实例。单例因其是单一实例而得名。通常使用单例的开发人员有特殊的类方法来访问它们。
现在我们了解了什么是单例,让我们讨论一下单例如何适应观察者模式。观察者模式用于一个对象响应另一对象的更改。在第二种情况下,我们有四个不同的视图控制器,它们都想了解底层数据的更改。 “底层数据”应该属于单个实例,即单例。 “了解变化”是通过观察对单例所做的变化来完成的。
家庭库存应用程序将具有一个类的单个实例,该类旨在管理库存项目列表。经理将管理一系列家居用品。以下是数据管理器的类定义:
当主库存项目的集合发生更改时,视图控制器需要了解此更改。上面的类定义并没有明确说明这是如何发生的。我们需要遵循观察者模式。视图控制器必须正式观察sharedManager。有两种方法可以观察另一个对象:
在场景二中,我们没有可以使用 KVO 观察到的 HouseholdInventoryManager 的单个属性。因为我们没有一个易于观察的属性,所以在这种情况下,观察者模式必须使用 NSNotificationCenter 来实现。四个视图控制器中的每一个都会订阅通知,并且sharedManager会在适当的时候向通知中心发送通知。库存管理器不需要了解有关视图控制器或任何其他类的实例的任何信息,这些类可能有兴趣了解库存项目集合何时发生变化; NSNotificationCenter 负责处理这些实现细节。视图控制器只是订阅通知,数据管理器只是发布通知。
许多初学者程序员利用了这样一个事实:在应用程序的生命周期中始终只有一个可全局访问的应用程序委托。初级程序员利用这一事实将对象和功能填充到 appDelegate 中,以方便从应用程序中的其他位置进行访问。仅仅因为 AppDelegate 是单例并不意味着它应该取代所有其他单例。这是一种糟糕的做法,因为它给一个类带来了太多负担,破坏了良好的面向对象实践。每个类都应该有一个清晰的角色,并且很容易解释,通常只需通过类的名称即可。
每当您的应用程序委托开始变得臃肿时,就开始将功能删除到单例中。例如,核心数据堆栈不应该留在AppDelegate中,而应该放在它自己的类中,即coreDataManager类中。
参考
There is some good information in many of the answers given, but none address the question fully.
The question asks about passing information between view controllers. The specific example given asks about passing information between views, but given the self-stated newness to iOS, the original poster likely meant between viewControllers, not between views (without any involvement from the ViewControllers). It seems that all the answers focus on two view controllers, but what if the app evolves to need to involve more than two view controllers in the information exchange?
The original poster also asked about Singletons and the use of the AppDelegate. These questions need to be answered.
To help anyone else looking at this question, who wants a full answer, I'm going to attempt to provide it.
Application Scenarios
Rather than having a highly hypothetical, abstract discussion, it helps to have concrete applications in mind. To help define a two-view-controller situation and a more-than-two-view-controller situation, I am going to define two concrete application scenarios.
Scenario one: maximum two view controllers ever need to share information.
See diagram one.
There are two view controllers in the application. There is a ViewControllerA (Data Entry Form), and View Controller B (Product List). The items selected in the product list must match the items displayed in the text box in the data entry form. In this scenario, ViewControllerA and ViewControllerB must communicate directly with each other and no other view controllers.
Scenario two: more than two view controllers need to share the same information.
See diagram two.
There are four view controllers in the application. It is a tab-based application for managing home inventory. Three view controllers present differently filtered views of the same data:
Any time an individual item is created or edited, it must also synchronize with the other view controllers. For example, if we add a boat in ViewControllerD, but it is not yet insured, then the boat must appear when the user goes to ViewControllerA (Luxury Items), and also ViewControllerC (Entire Home Inventory), but not when the user goes to ViewControllerB (Non-insured Items). We need be concerned with not only adding new items, but also deleting items (which may be allowed from any of the four view controllers), or editing existing items (which may be allowed from the "Add New Item Form", repurposing the same for editing).
Since all the view controllers do need to share the same data, all four view controllers need to remain in synchronization, and therefore there needs to be some sort of communication to all other view controllers, whenever any single view controller changes the underlying data. It should be fairly obvious that we do not want each view controller communicating directly with each other view controller in this scenario. In case it is not obvious, consider if we had 20 different view controllers (rather than just 4). How difficult and error-prone would it be to notify each of the other 19 view controllers any time one view controller made a change?
The Solutions: Delegates and the Observer Pattern, and Singletons
In scenario one, we have several viable solutions, as other answers have given
In scenario two, we have other viable solutions:
A singleton is an instance of a class, that instance being the only instance in existence during its lifetime. A singleton gets its name from the fact that it is the single instance. Normally developers who use singletons have special class methods for accessing them.
Now that we understand what a singleton is, let's discuss how a singleton fits into the observer pattern. The observer pattern is used for one object to respond to changes by another object. In the second scenario, we have four different view controllers, who all want to know about changes to the underlying data. The "underlying data" should belong to a single instance, a singleton. The "know about changes" is accomplished by observing changes made to the singleton.
The home inventory application would have a single instance of a class which is designed to manage a list of inventory items. The manager would manage a collection of household items. The following is a class definition for the data manager:
When the collection of home inventory items changes, the view controllers need to be made aware of this change. The class definition above does not make it obvious how this will happen. We need to follow the observer pattern. The view controllers must formally observe the sharedManager. There are two ways to observe another object:
In scenario two, we do not have a single property of the HouseholdInventoryManager which could be observed using KVO. Because we do not have a single property which is easily observable, the observer pattern, in this case, must be implemented using NSNotificationCenter. Each of the four view controllers would subscribe to notifications, and the sharedManager would send notifications to the notification center when appropriate. The inventory manager does not need to know anything about the view controllers or instances of any other classes which may be interested in knowing when the collection of inventory items changes; the NSNotificationCenter takes care of these implementation details. The View Controllers simply subscribe to notifications, and the data manager simply posts notifications.
Many beginner programmers take advantage of the fact that there is always exactly one Application Delegate in the lifetime of the application, which is globally accessible. Beginning programmers use this fact to stuff objects and functionality into the appDelegate as a convenience for access from anywhere else in the application. Just because the AppDelegate is a singleton doesn't mean it should replace all other singletons. This is a poor practice as it places too much burden on one class, breaking good object-oriented practices. Each class should have a clear role that is easily explained, often just by the name of the class.
Any time your Application Delegate starts to get bloated, start to remove functionality into singletons. For example, the Core Data Stack should not be left in the AppDelegate, but should instead be put in its own class, a coreDataManager class.
References
将数据从 ViewController 2(目标)传递回 viewController 1(源)是更有趣的事情。
假设您使用storyBoard,这些是我发现的所有方法:
这些已经在这里讨论过。
我发现还有更多方法:
使用Block回调:
在VC1中的
prepareForSegue
方法中使用使用storyboards Unwind(退出)
实现一个方法在 VC 1 中使用 UIStoryboardSegue 参数,如下所示:
在 StoryBoard 中,将“返回”按钮挂接到 VC 的绿色退出按钮(展开)上。现在你有了一个“返回”的segue,因此你可以在VC2的prepareForSegue中使用destinationViewController属性,并且
在 VC1 返回之前更改 VC1 的任何属性。
使用故事板Undwind(退出)的另一种选择 - 您可以使用您在VC1中编写的方法
,并且在VC1的prepareForSegue中您可以更改您想要共享的任何属性。
在这两个展开选项中,您都可以设置按钮的 tag 属性并在prepareForSegue 中检查它。
Passing data back from ViewController 2 (destination) to viewController 1 (source) is the more interesting thing.
Assuming you use storyBoard, these are all the ways I found out:
Those were discussed here already.
I found there are more ways:
Using Block callbacks:
Use it in the
prepareForSegue
method in the VC1Using storyboards Unwind (Exit)
Implement a method with a UIStoryboardSegue argument in VC 1,like this one:
In the storyBoard, hook the "return" button to the green Exit button (Unwind) of the vc. Now you have a segue that "goes back" so you can use the destinationViewController property in the prepareForSegue of VC2 and
change any property of VC1 before it goes back.
Another option of using storyboards Undwind (Exit) - you can use the method you wrote in VC1
And in the prepareForSegue of VC1 you can change any property you want to share.
In both unwind options, you can set the tag property of the button and check it in the prepareForSegue.
OP 没有提到视图控制器,但很多答案都提到了,我想补充一下 LLVM 的一些新功能允许在想要将数据从一个视图控制器传递到另一个视图控制器时变得更容易,然后得到一些结果。
Storyboard segues、ARC 和 LLVM 块使这对我来说比以往任何时候都更容易。上面的一些答案已经提到了故事板和续集,但仍然依赖于委托。定义委托当然有效,但有些人可能会发现传递指针或代码块更容易。
使用 UINavigators 和 segues,可以通过简单的方法将信息传递给从属控制器并取回信息。 ARC 使传递指向从 NSObject 派生的对象的指针变得简单,因此如果您希望从属控制器为您添加/更改/修改某些数据,请将其传递给可变实例的指针。块使传递操作变得容易,因此如果您希望从属控制器调用更高级别控制器上的操作,请向其传递一个块。您可以定义该块来接受对您有意义的任意数量的参数。如果更适合的话,您还可以将 API 设计为使用多个块。
这里有两个关于连接胶的简单例子。第一个很简单,显示了为输入传递的一个参数,第二个为输出传递的参数。
第二个示例显示为第二个参数传递回调块。我喜欢使用块,因为它使源代码(更高级别的源代码)中的相关细节紧密结合在一起。
The OP didn't mention view controllers but so many of the answers do, that I wanted to chime in with what some of the new features of the LLVM allow to make this easier when wanting to pass data from one view controller to another and then getting some results back.
Storyboard segues, ARC and LLVM blocks make this easier than ever for me. Some answers above mentioned storyboards and segues already but still relied on delegation. Defining delegates certainly works but some people may find it easier to pass pointers or code blocks.
With UINavigators and segues, there are easy ways of passing information to the subservient controller and getting the information back. ARC makes passing pointers to things derived from NSObjects simple so if you want the subservient controller to add/change/modify some data for you, pass it a pointer to a mutable instance. Blocks make passing actions easy so if you want the subservient controller to invoke an action on your higher level controller, pass it a block. You define the block to accept any number of arguments that makes sense to you. You can also design the API to use multiple blocks if that suits things better.
Here are two trivial examples of the segue glue. The first is straightforward showing one parameter passed for input, the second for output.
This second example shows passing a callback block for the second argument. I like using blocks because it keeps the relevant details close together in the source - the higher level source.
共享数据的方法有多种。
您始终可以使用
NSUserDefaults
共享数据。设置您想要与您选择的键共享的值,并从与下一个视图控制器中的该键关联的NSUserDefault
获取值。您只需在
viewcontrollerA
中创建一个属性即可。在viewcontrollerB
中创建一个viewcontrollerA
对象,并将所需的值分配给该属性。您还可以为此创建自定义委托。
There are multiple methods for sharing data.
You can always share data using
NSUserDefaults
. Set the value you want to share with respect to a key of your choice and get the value fromNSUserDefault
associated to that key in the next view controller.You can just create a property in
viewcontrollerA
. Create an object ofviewcontrollerA
inviewcontrollerB
and assign the desired value to that property.You can also create custom delegates for this.
在视图控制器之间传递数据有多种选项。
我将使用最新的 iOS 框架在 Swift 中重写他的逻辑
第 1 步。 在 ViewControllerB 中声明变量
第 2 步。 打印ViewControllerB' ViewDidLoad 方法中的变量
第 3 步。 在 ViewControllerA 中通过导航控制器推送数据时传递数据
因此,这里是完整的代码:
ViewControllerA
ViewControllerB
第 1 步。 创建从 ViewControllerA 到 ViewControllerB 的 Segue,并在 Storyboard 中指定 Identifier = showDetailSegue,如下所示
< a href="https://i.sstatic.net/fWzeW.png" rel="noreferrer">
步骤 2. 在 ViewControllerB 中声明一个名为 isSomethingEnabled 的可行变量并打印其值。
第3步。在ViewControllerA中传递isSomethingEnabled的值,同时传递Segue
所以这里是完整的代码:
ViewControllerA
ViewControllerB
第 1 步。声明协议ViewControllerBDelegate在 ViewControllerB 文件中,但在类之外
第 2 步。 在 ViewControllerB 中声明 Delegate 变量实例
第 3 步。 在 ViewControllerB 的 viewDidLoad 方法内部发送委托数据
第 4 步。 确认 ViewControllerA 中的 ViewControllerBDelegate
第 5 步。 确认您将在 ViewControllerA 中实现委托
第 6 步。 在 ViewControllerA 中实现用于接收数据的委托方法
所以这里 是以下完整代码:
ViewControllerA
ViewControllerB
步骤1.在ViewControllerB中的通知观察者中设置并发布数据
步骤2.在ViewControllerA中添加通知观察者
步骤3.接收通知ViewControllerA 中的数据值
所以这里是完整的代码:
ViewControllerA
ViewControllerB
步骤1.在ViewControllerB中声明块
步骤2.在ViewControllerB中的块中设置数据
步骤3.在ViewControllerA中接收块数据
所以这里是完整的代码:
ViewControllerA
ViewControllerB
您可以在我的 GitHub 上找到完整的示例应用程序 如果您对此有任何疑问,请告诉我。
There are multiple options for passing data between view controllers.
I am going to rewrite his logic in Swift with the latest iOS framework
Step 1. Declare variable in ViewControllerB
Step 2. Print Variable in ViewControllerB' ViewDidLoad method
Step 3. In ViewControllerA Pass Data while pushing through Navigation Controller
So here is the complete code for:
ViewControllerA
ViewControllerB
Step 1. Create Segue from ViewControllerA to ViewControllerB and give Identifier = showDetailSegue in Storyboard as shown below
Step 2. In ViewControllerB Declare a viable named isSomethingEnabled and print its value.
Step 3. In ViewControllerA pass isSomethingEnabled's value while passing Segue
So here is the complete code for:
ViewControllerA
ViewControllerB
Step 1. Declare Protocol ViewControllerBDelegate in the ViewControllerB file, but outside the class
Step 2. Declare Delegate variable instance in ViewControllerB
Step 3. Send data for delegate inside viewDidLoad method of ViewControllerB
Step 4. Confirm ViewControllerBDelegate in ViewControllerA
Step 5. Confirm that you will implement a delegate in ViewControllerA
Step 6. Implement delegate method for receiving data in ViewControllerA
So here is the complete code for:
ViewControllerA
ViewControllerB
Step 1. Set and post data in the notification observer in ViewControllerB
Step 2. Add Notification Observer in ViewControllerA
Step 3. Receive Notification data value in ViewControllerA
So here is the complete code for:
ViewControllerA
ViewControllerB
Step 1. Declare block in ViewControllerB
Step 2. Set data in block in ViewControllerB
Step 3. Receive block data in ViewControllerA
So here is the complete code for:
ViewControllerA
ViewControllerB
You can find complete sample Application at my GitHub Please let me know if you have any question(s) on this.
如果要将数据从一个控制器传递到另一个控制器,请尝试以下代码:
File FirstViewController.h
SecondViewController.h
File FirstViewController.m
If you want to pass data from one controller to other, try this code:
File FirstViewController.h
SecondViewController.h
File FirstViewController.m
这是一个非常古老的答案,这是反模式。请使用代表。不要使用这种方法!!
1. 在第二个视图控制器中创建第一个视图控制器的实例,并使其属性
@property (nonatomic,assign)
。2. 分配此视图控制器的
SecondviewController
实例。2.完成选择操作后,将数组复制到第一个视图控制器。当您卸载第二个视图时,第一个视图将保存数组数据。
This is a very old answer and this is anti pattern. Please use delegates. Do not use this approach!!
1. Create the instance of the first view controller in the second view controller and make its property
@property (nonatomic,assign)
.2. Assign the
SecondviewController
instance of this view controller.2. When you finish the selection operation, copy the array to the first View Controller. When you unload the second view, the first view will hold the array data.
我寻找这个解决方案很长时间,终于找到了。首先,在 SecondViewController.h 文件中声明所有对象,就像
现在在实现文件中一样,为这些对象分配内存,如下所示:
现在您已经为 Array 和对象分配了内存。现在,您可以在推送此 ViewController 之前填充该内存。
转到 SecondViewController.h 并编写两个方法:
在实现文件中,您可以实现以下功能:
期望您的
CustomObject
必须具有一个 setter 函数。现在你的基本工作已经完成。转到您想要推送
SecondViewController
的位置并执行以下操作:注意拼写错误。
I was searching this solution for long time, and at last I found it. First of all, declare all the objects in your SecondViewController.h file like
Now in your implementation file, allocate the memory for those objects like this:
Now you have allocated the memory for
Array
and object. Now you can fill that memory before pushing thisViewController
.Go to your SecondViewController.h and write two methods:
In the implementation file, you can implement the function:
Expecting that your
CustomObject
must have a setter function with it.Now your basic work is done. Go to the place where you want to push the
SecondViewController
and do the following stuff:Take care for spelling mistakes.
这不是这样做的方法。您应该使用代表。
我假设我们有两个视图控制器,ViewController1 和 ViewController2,并且此检查位于第一个视图控制器中,当其状态发生变化时,您想要在 ViewController2 中执行某些操作。为了以正确的方式实现这一点,您应该执行以下操作:
将新文件添加到您的项目(Objective-C 协议)菜单文件→新建。现在将其命名为 ViewController1Delegate 或任何您想要的名称,并在 @interface 和 @end 指令之间编写这些内容:
现在转到 ViewController2.h 并添加:
然后将其定义更改为:
现在转到 ViewController2.m 并在实现中添加:
现在转到ViewController1.h 并添加以下属性:
现在,如果您在某个事件发生后在 ViewController2 内创建 ViewController1,那么您应该使用 NIB 文件以这种方式执行此操作:
现在您已全部设置完毕。每当您检测到 ViewController1 中的 check 更改事件时,您所要做的就是以下内容:
This is not the way to do it. You should use delegates.
I'll assume we have two view controllers, ViewController1 and ViewController2, and this check thing is in the first one and when its state changes, you want to do something in ViewController2. To achieve that in the proper way, you should do the below:
Add a new file to your project (Objective-C Protocol) menu File → New. Now name it ViewController1Delegate or whatever you want and write these between the @interface and @end directives:
Now go to ViewController2.h and add:
Then change its definition to:
Now go to ViewController2.m and inside the implementation add:
Now go to ViewController1.h and add the following property:
Now if you are creating ViewController1 inside ViewController2 after some event, then you should do it this way using NIB files:
Now you are all set. Whenever you detect the event of check changed in ViewController1, all you have to do is the below:
如果您想将数据从一个视图控制器发送到另一个视图控制器,可以使用以下一种方法:
假设我们有视图控制器:viewControllerA 和 viewControllerB
现在位于文件 viewControllerB.h
文件中 viewControllerB.m:
在文件 viewControllerA.m 中:
这就是您如何将数据从 viewControllerA 传递到 viewControllerB 而无需设置任何委托。 ;)
If you want to send data from one to another viewController, here's a way to do it:
Say we have viewControllers: viewControllerA and viewControllerB
Now in file viewControllerB.h
In file viewControllerB.m:
In file viewControllerA.m:
So this is how you can pass data from viewControllerA to viewControllerB without setting any delegate. ;)
凭借 Swift 的倾向并想要一个简单的示例,如果您使用 Segue 来解决问题,这里是我传递数据的首选方法。
它与上面类似,但没有按钮、标签等。只是简单地将数据从一个视图传递到下一个视图。
设置情节提要
共有三个部分。
这是一个非常简单的视图布局,它们之间有一个 segue。
这是发送者的设置
这是接收方的设置。
最后,segue 的设置。
视图控制器
我们保持简单,因此没有按钮和操作。我们只是在应用程序加载时将数据从发送方移动到接收方,然后将传输的值输出到控制台。
该页面获取最初加载的值并将其传递。
该页面仅在加载时将变量的值发送到控制台。至此,我们最喜欢的电影应该在该变量中。
如果您想使用 Segue 并且您的页面没有位于导航控制器下,这就是您可以解决此问题的方法。
一旦运行,它应该自动切换到接收者视图,并将值从发送者传递到接收者,并在控制台中显示该值。
With a Swift slant and want a bare-bones example, here is my go-to method for passing data if you are using a segue to get around.
It is similar to the above but without the buttons, labels and such. Just simply passing data from one view to the next.
Setup The Storyboard
There are three parts.
This is a very simple view layout with a segue between them.
Here is the setup for the sender
Here is the setup for the receiver.
Lastly, the setup for the segue.
The View Controllers
We are keeping this simple so no buttons and not actions. We are simply moving data from the sender to the receiver when the application loads and then outputting the transmitted value to the console.
This page takes the initially loaded value and passes it along.
This page just sends the value of the variable to the console when it loads. By this point, our favorite movie should be in that variable.
That is how you can tackle it if you want to use a segue and you don't have your pages under a navigation controller.
Once it is run, it should switch to the receiver view automatically and pass the value from the sender to the receiver, displaying the value in the console.
就我而言,我使用了一个单例类,它可以作为全局对象工作,允许从应用程序中的几乎所有位置访问数据。
首先是建立一个单例类。请参阅页面我的 Objective-C 单例应该是什么样子喜欢?。
为了使该对象全局可访问,我只需将其导入到
appName_Prefix.pch
中,用于在每个类中应用 import 语句。为了访问并使用这个对象,我简单地实现了一个类方法来返回共享实例,该实例包含它自己的变量。
In my case, I used a singleton class which could work as a global object allowing accesses to the data from almost everywhere in the app.
The first thing is to build a singleton class. Please refer to the page What should my Objective-C singleton look like?.
And to make the object globally accessible, I simply imported it in
appName_Prefix.pch
which was for applying import statement in every classes.To access this object and to use it, I simply implemented a class method to return the shared instance, which contains its own variables.
在 FirstViewController 和 SecondViewController 之间传递数据如下
例如:
FirstViewController String value as
所以我们可以使用以下步骤在第二个类中传递这个值:
我们需要在 < 中创建一个字符串对象em>SecondViewController.h 文件
需要在 .h 文件中声明一个属性,如下所示
需要在标头声明下方的 FirstViewController.m 文件中合成该值
在文件FirstViewController.h中:
在 FirstViewController 中,我们从哪个方法导航到第二个视图,请在该方法中写入以下代码。
Passing data between FirstViewController to SecondViewController as below
For example:
FirstViewController String value as
So we can pass this value in the second class using the below steps:
We need to create a string object in the SecondViewController.h file
Need to declare a property as the below declaration in the .h file
Need synthesize that value in the FirstViewController.m file below the header declaration
And in file FirstViewController.h:
In FirstViewController, from which method we navigate to the second view, please write the below code in that method.
我目前正在通过一个名为 MCViewFactory 的项目为这个问题的开源解决方案做出贡献,该项目可以在这里找到:
Manticore iOS View Factory
这个想法是模仿 Android 的意图范例,使用全局工厂来管理您正在查看的视图,并使用“意图”在视图之间切换和传递数据。所有文档都位于 GitHub 页面上,但这里有一些亮点:
您可以在 .XIB 文件中设置所有视图,并将它们注册到应用程序委托中,同时初始化工厂。
现在,在视图控制器 (VC) 中,只要您想要移动到新的 VC 并传递数据,您就可以创建一个新意图并将数据添加到其字典 (savedInstanceState) 中。然后,只需设置工厂的当前意图:
所有符合此要求的视图都需要是 MCViewController 的子类,它允许您重写新的 onResume: 方法,从而允许您访问传入的数据。
I am currently contributing to an open source solution to this problem through a project called MCViewFactory, which may be found here:
Manticore iOS View Factory
The idea is imitate Android's intent paradigm, using a global factory to manage which view you are looking at and using "intents" to switch and pass data between views. All the documentation is on the GitHub page, but here are some highlights:
You setup all your views in .XIB files and register them in the app delegate, while initializing the factory.
Now, in your view controller (VC), anytime you want to move to a new VC and pass data, you create a new intent and add data to its dictionary (savedInstanceState). Then, just set the current intent of factory:
All of your views that conform to this need to be subclasses of MCViewController, which allow you to override the new onResume: method, allowing you access to the data you've passed in.
在下一个视图控制器 .h 文件中创建属性并定义 getter 和 setter。
在 nextVC 上的 NextVC.h 中添加此
属性
:在 NextVC.m 中添加
@synthesize indexNumber;
最后
Create the property in the next
view controller .h
file and define getters and setters.Add this
property
in NextVC.h on nextVC:Add
@synthesize indexNumber;
in NextVC.mAnd last
有很多方法可以做到这一点,选择正确的方法很重要。最大的架构决策之一可能在于如何在整个应用程序中共享或访问模型代码。
我不久前写了一篇关于此的博客文章:共享模型代码。下面是一个简短的总结:
共享数据
一种方法是在视图控制器之间共享指向模型对象的指针。
因为准备segue是最常见的,这里是一个示例:
独立访问
另一种方法是一次处理充满数据的屏幕,而不是将视图控制器彼此耦合,而是将每个视图控制器耦合到它们可以独立访问的单个数据源。
我见过的最常见的方法是 singleton 实例。因此,如果您的单例对象是 DataAccess,您可以在 UIViewController 的 viewDidLoad 方法中执行以下操作:
还有其他工具也可以帮助传递数据:
核心数据
核心数据的好处在于它具有反向关系。因此,如果您只想为 NotesViewController 提供注释对象,则可以,因为它与笔记本等其他内容具有反比关系。如果您需要 NotesViewController 中笔记本上的数据,您可以通过执行以下操作来返回对象图:
在我的博客文章中阅读有关此内容的更多信息:共享模型代码
There are tons of ways to do this and it's important to pick the right one. Probably one of the biggest architectural decisions lies on how the model code will be shared or accessed throughout the app.
I wrote a blog post about this a while back: Sharing Model Code. Here's a brief summary:
Shared data
One approach is to share pointers to the model objects between view controllers.
Since prepare for segue is the most common here is an example:
Independent access
Another approach is to handle a screen full of data at a time and instead of coupling the view controllers to each other couple each view controller to single data source that they can get to independently.
The most common way I've seen this done is a singleton instance. So if your singleton object was
DataAccess
you could do the following in the viewDidLoad method of UIViewController:There are addition tools that also help pass along data:
Core Data
The nice thing about Core Data is that it has inverse relationships. So if you want to just give a NotesViewController the notes object you can because it'll have an inverse relationship to something else like the notebook. If you need data on the notebook in the NotesViewController you can walk back up the object graph by doing the following:
Read more about this in my blog post: Sharing Model Code
如果您想将数据从 ViewControlerOne 传递到 ViewControllerTwo,请尝试这些...
在 ViewControlerOne.h 中执行这些操作:
在 ViewControllerTwo.h 中执行这些操作:
在 ViewControllerTwo.m 中合成 str2:
在 ViewControlerOne.m 中执行这些操作:
O 按钮单击事件,执行此操作:
在 ViewControllerTwo.m 中执行以下操作:
If you want to pass data from ViewControlerOne to ViewControllerTwo, try these...
Do these in ViewControlerOne.h:
Do these in ViewControllerTwo.h:
Synthesize str2 in ViewControllerTwo.m:
Do these in ViewControlerOne.m:
O the buttons click event, do this:
Do these in ViewControllerTwo.m:
您可以将数据保存在应用程序委托中,以便跨应用程序中的视图控制器访问它。您所要做的就是创建应用程序委托的共享实例:
例如
如果您声明一个
NSArray 对象 *arrayXYZ
,那么您可以通过以下方式在任何视图控制器中访问它:appDelegate.arrayXYZ
。You can save data in an App delegate to access it across view controllers in your application. All you have to do is create a shared instance of an app delegate:
For Example
If you declare a
NSArray object *arrayXYZ
, then you can access it in any view controller byappDelegate.arrayXYZ
.