我是iOS新手。我在ViewControllers之间传递数据时遇到问题。 我有三个viewControllers(view_1,view_2和view_3)。
我的设置: -
我想将'view_1'的ViewController引用(id)发送到'view_3'。所以我在'view_1'中包含include "view_3"
,并将值设置为'view_3'变量(使用view_3 *v3=[[view_3 alloc] init ]; v3.reference=self;
)。在控制台中显示:
查看控制器: - ; < ViewController:0x89e9540>
在“view_1”中,但在“view_3”中,在控制台中显示
查看控制器(null)
但是,当我使用'view_2'传递这些数据时,它的工作。但是怎么样?我想知道这种行为,是否有任何解决方案来创建它?
请帮忙。
答案 0 :(得分:46)
"将数据传递到目标控制器"当触发segue时,将通过重写方法prepareForSegue:sender:
来实现。
通常,您将数据而不是源视图控制器传递给目标视图控制器。 "数据"可能是您的应用程序的某个方面" model"。它是一个像" User"这样的对象,或者可能是一个包含" User"等的数组。
目标视图控制器 视图控制器 这意味着,目标视图控制器不需要导入源视图控制器的标头。
另一方面,源视图控制器可能知道目标视图控制器的具体类或目标视图控制器的base 类,因此将导入目标视图控制器的标头。
请参阅:Configuring the Destination Controller When a Segue is Triggered
如果您需要某种"通信协议"在源和目标之间,您可以使用委派与其他视图控制器进行通信。这涉及定义@protocol(例如,具有方法doneButton
)和属性delegate
,其在目标视图控制器中定义。如果目标视图控制器的特定到目标视图控制器,则应在目标视图控制器的标头中定义该协议。通常,您从目标控制器的角度定义协议,而不是源控制器的要求。
源视图控制器然后创建一个委托(除非它本身就是它)并设置目标视图控制器的delegate
。目标视图控制器将委托方法发送给委托,委托处理它。
现在,传递"数据"从VC_A到VC_B应该是直截了当的。您应该阅读一些使用prepareForSegue:sender:
的示例。例如,目标视图控制器可能具有属性data
,表示应显示的事物。源视图控制器必须在prepareForSegue:sender:
。
通过VC_B将数据从VC_A传递到VC_C也应该是直截了当的。
注意:每个视图控制器都可以定制(分离,修改,准备,切片,转换等) data
以使其成为合适的{ {1}}用于下一个视图控制器。
如果VC_C需要其源视图控制器VC_B中没有的数据,那么有几种方法可以解决这个问题。但是,这通常是糟糕设计的标志。
你可以拥有一个应用程序模型,它是全局。假设您的应用模型"是data
类型的对象。假设在任何时候只有该应用程序模型的一个实例。然后,该模型是" Singleton",可以从您的应用中的任何位置访问,如下所示:
Document
但是,获取模型实例的首选方法是在第一个视图控制器中,该控制器需要访问它,在这种情况下:VC_A。
然后,VC_A将Document* document = [Document sharedDocument];
实例传递给下一个视图控制器VC_B。 VC_B将文档对象传递给VC_C。
您应该阅读官方文档" View Controller Programming Guide for iOS"。
假设您有一个列表"用户"。该列表应显示在表视图控制器中,并且还应该有一个详细视图,显示一个用户的详细信息。
表格视图控制器将有一个"数据"财产Document
:
在 UsersTableViewController.h :
users
(严格来说,这个@interface UsersTableViewController : UIViewController
@property (nonatomic, readonly) NSArray* users;
@end
属性并不需要公开。例如,如果表视图在内部获取用户自己的列表,则无需从外部访问它。
"用户" array是表视图的 data ,它应以行的形式显示。每一行都显示一个"摘要"用户。
用户的更多详细信息应显示在详细信息视图控制器中。详细视图控制器的数据是user
类型的单个用户。
当用户在表格视图中选中某一行时,将显示详细视图控制器。在显示之前,表视图控制器必须配置详细视图控制器:表视图控制器分配详细视图控制器"数据属性"当前选定的用户。因此,详细视图控制器应具有 public 属性User
:
user
表视图控制器在@interface UserViewController : UIViewController
@property (nonatomic) User* user;
@end
:
在 UsersTableViewController.m
中prepareForSegue:sender:
第二个例子更复杂,使用"代表团"作为在控制器之间建立通信的手段。
警告:
这不是一个完整的例子。本示例的目的是演示如何使用" Delegation"。如示例中所示的全功能数据任务实现将需要更多的努力。在这样的场景中,"代表团"将是实现这一目标的最佳方法(恕我直言)。
假设我们想要
从详细视图中。
这些"数据任务"不应由详细视图控制器本身执行,而委托负责这些数据任务。
这些数据操作应由代表处理:
- (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:@"ShowUserDetails"]) {
UserViewController* userViewController = [segue destinationViewController];
userViewController.user = [self.users objectInListAtIndex:[self.tableView indexPathForSelectedRow].row];
}
}
该协议反映了基本的CRUD方法(创建,读取,更新,删除)。
同样,我们不希望详细视图控制器本身执行这些数据方法,而是由实现@protocol UserDataSourceDelegateProtocol <NSObject>
- (User*) viewControllerUser:(UserViewControllerBase*)viewController;
- (void) viewController:(UserViewControllerBase*)viewController dismissWithUpdatedUser:(User*)user;
- (void) viewController:(UserViewControllerBase*)viewController dismissWithDeletedUser:(User*)user;
- (void) viewController:(UserViewControllerBase*)viewController dismissWithCreatedUser:(User*)user;
@end
的实例执行此操作。详细视图控制器具有该委托的属性,并且它发送这些&#34;数据任务&#34;代表。
可能有几个详细视图控制器,抽象类UserDataSourceDelegateProtocol
的所有子类,它们处理 show ,编辑和创建任务。可以在表格视图和&#34;显示用户&#34;中执行用户删除。查看控制器:
UserViewControllerBase
ShowUserViewController
EditUserViewController
例如,NewUserViewController
会在用户选中&#34;返回&#34;时发送EditUserViewController
。按钮AND如果用户已修改用户对象。现在,代表可能允许也可能不允许关闭详细视图。例如,当存在验证错误时,它可能会禁止它。
viewController:dismissWithUpdatedUser:
协议可以在根视图控制器中实现,例如表视图控制器。但是,一个单独的类,其唯一的责任是处理数据任务可能更合适。在下面的示例中,表视图控制器也将是此数据处理程序。
UserDataSourceDelegateProtocol
可以在额外的标题中定义。
在 UsersTableViewController.m :
中UserDataSourceDelegateProtocol
此处,Table View Controller配置Show User Detail View Controller:
#import "UserDataSourceDelegateProtocol.h"
#import "ShowUserViewController.h"
@interface UsersTableViewController () <UserDataSourceDelegateProtocol>
@property (nonatomic, readonly) NSArray* users;
@end
// This delegate will be called when the detail view controller request
// the user object which shall be displayed.
- (User*) viewControllerUser:(UserViewControllerBase*)viewController {
return [self.users objectInListAtIndex:[self.tableView indexPathForSelectedRow].row];
}
&#34;编辑用户&#34;视图控制器通常是&#34;显示用户&#34;的目标视图控制器。视图控制器,当用户选中&#34;编辑&#34;按钮。
&#34;显示用户&#34;视图控制器将设置代理 &#34;编辑用户&#34;视图控制器获取相同的委托:
在 ShowUserViewController.m
中- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:UserShowSegueID])
{
ShowUserViewController* showViewController = segue.destinationViewController;
showViewController.delegate = self; // Data Source Handler is self
}
}
数据委托可以按如下方式处理更新的用户:
在 UsersTableViewController.m :
中- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:UserEditSegueID])
{
EditUserViewController* editViewController = segue.destinationViewController;
editViewController.delegate = self.delegate; // pass through the data source hanlder
}
}
答案 1 :(得分:11)
This Swift project帮助我终于明白了如何做到这一点。
我在类似的行上设置了一个简单的例子。在文本字段中写入一些文本,按下按钮,然后将文本放在下一个视图控制器的标签中。
这不是很困难。在Interface Builder中创建故事板布局。要制作segue,只需 control ,单击按钮并拖动到第二视图控制器。
第一视图控制器的代码是
import UIKit
class FirstViewController: UIViewController {
@IBOutlet weak var textField: UITextField!
// This function is called before the segue
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
// get a reference to the second view controller
let secondViewController = segue.destinationViewController as! SecondViewController
// set a variable in the second view controller with the String to pass
secondViewController.receivedString = textField.text!
}
}
第二视图控制器的代码是
import UIKit
class SecondViewController: UIViewController {
@IBOutlet weak var label: UILabel!
// This variable will hold the data being passed from the First View Controller
var receivedString = ""
override func viewDidLoad() {
super.viewDidLoad()
// Used the text from the First View Controller to set the label
label.text = receivedString
}
}
UITextField
和UILabel
。将数据传递给第三视图控制器的过程将是相同的。
答案 2 :(得分:2)
你有一个解决方案,但不是最恰当的方式。
ViewController3.h
-(void)getUser:(NSString *)strPassedUser;
转到你的ViewController3.m并在@interface上面添加一个像这样的变量
NSString *recievingVariable ;
然后在ViewController3.m内部的一些
-(void)getUser:(NSString *)strPassedUser
{
recievingVariable = strPassedUser;
}
ViewController1并导入ViewController3 然后这样做..
ViewController3 * vc3 = [ViewController3 alloc]getUser :@"me"];
在这种情况下,您的函数getUser
将被调用,您将获得receivingVariable= me
。
答案 3 :(得分:1)
更好,更轻松的解决方案。
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Main" bundle:nil];
UIViewController *vc = [storyboard instantiateViewControllerWithIdentifier:@"webView"];
webView = (WebViewController *)vc;
webView.strWebLink = @"http://www.Google.com/";
[self.navigationController showViewController:vc sender:self];
答案 4 :(得分:1)
软件工程中的Singleton模式是一种设计模式,它确保一个类只有一个实例,并提供一个全局访问点。
由于它具有唯一的实例,因此在整个应用程序/命名空间中共享类变量和方法。
示例:
class Singleton {
static let sharedInstance = Singleton()
var studentId = 1281
}
您可以在App中的任何位置使用它:
var studentId = Singleton.sharedInstance.studentId
print("Student Id: \(studentId)")
答案 5 :(得分:1)
在Swift 4.0中
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let vc = segue.destination as! SecondViewController
vc.username = self.username
}
确保
segue.destination
在这里真的不同。