UISplitView,在设置代表时接收语义问题
Posted
技术标签:
【中文标题】UISplitView,在设置代表时接收语义问题【英文标题】:UISplitView, Receiving Semantic Issues in setting up delegates 【发布时间】:2012-11-16 19:43:45 【问题描述】:我一直在关注 Big Nerd Ranch 的 ios 编程指南(第 3 版)来设置我的 Xcode 项目,该项目显示我公司产品的列表,然后是每个产品的详细视图。
我让应用程序按照我需要的方式流畅地运行,但是当我试图想象用户体验时,我开始遇到麻烦。为 iPad 添加 UISplitViewController 让我头疼欲裂,浪费了许多下午。
目前,我收到有关委托相关代码的语义问题的报告。一个在 DetailViewController.h 中,另一个在 ListViewController.m 中。
我会在发布之前总结一下我对这段代码的意图,但由于我缺乏经验,我可能会错过一些微妙之处:
AppDelegate 分配 UITableViewController(ListViewController 类)和 UIViewController(DetailViewController 类),然后检查是否有 iPad。如果是 iPad,它会使用两个视图的数组创建一个 UISplitViewController。否则它将 ListViewController 加载为主视图。
在我尝试在两个视图之间创建委托关系之前,应用程序已成功构建,但 iPad UISplitViewController 仅加载了一个空的详细视图。 iphone 加载 ListViewController,然后选择一行显示一个空的详细视图 (DetailViewController)。当您返回 TableView 并选择相同或另一个表格单元格时,正确的信息将加载到 DetailView 中。这让我相信 TableView 的初始实例没有正确传递选择,但返回它(重新分配它?)会纠正问题。我希望委托设置能解决这个问题。由于我无法使该部分正常工作,因此我无法测试该理论。我只是想我会提到它。
关于 UISplitViewController 问题和教程,我已经尽我所能(正确的关键字和搜索词使我无法理解)环顾四周,但它们都与我在项目中已经设置的内容大不相同,无论是应用程序的行为还是代码的整体结构。当我看起来如此接近时,我宁愿不必重新开始。
我打开了 BigNerdRanch 示例代码(它确实有效),正如我所说,唯一的区别似乎与我想要显示我的信息的方式有关。在这一点上,我需要一些帮助,以找出我做错了什么。
提前致谢!
AppDelegate.m:
#import "ProductFeedAppDelegate.h"
#import "ListViewController.h"
#import "DetailViewController.h"
@implementation ProductFeedAppDelegate
@synthesize window = _window;
@synthesize managedObjectContext = _managedObjectContext;
@synthesize managedObjectModel = _managedObjectModel;
@synthesize persistentStoreCoordinator = _persistentStoreCoordinator;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
ListViewController *lvc = [[ListViewController alloc] initWithStyle:UITableViewStylePlain];
UINavigationController *masterNav = [[UINavigationController alloc] initWithRootViewController:lvc];
DetailViewController *dvc = [[DetailViewController alloc] init];
[lvc setDetailViewController:dvc];
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
UINavigationController *detailNav = [[UINavigationController alloc] initWithRootViewController:dvc];
NSArray *vcs = [NSArray arrayWithObjects:masterNav, detailNav, nil];
UISplitViewController *svc = [[UISplitViewController alloc] init];
//set delegate
[svc setDelegate:dvc];
[svc setViewControllers:vcs];
[[self window] setRootViewController:svc];
else
[[self window] setRootViewController:masterNav];
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
//... trimmed out some template code to spare you
@end
` ListViewController.h:
#import <Foundation/Foundation.h>
#import "ProductItemCell.h"
//#import "ItemStore.h"
#import "DetailViewController.h"
@class DetailViewController;
@class RSSChannel;
@interface ListViewController : UITableViewController
RSSChannel *channel;
@property (nonatomic, strong) DetailViewController *detailViewController;
-(void)fetchEntries;
@end
//A new protocol named ListViewControllerDelegate
@protocol ListViewControllerDelegate
//Classes that conform to this protocol must implement this method:
- (void)listViewController:(ListViewController *)lvc handleObject:(id)object;
@end
ListViewController.m:
#import "ListViewController.h"
#import "RSSChannel.h"
#import "RSSItem.h"
#import "DetailViewController.h"
#import "ContactViewController.h"
#import "FeedStore.h"
@implementation ListViewController
@synthesize detailViewController;
- (void)transferBarButtonToViewController:(UIViewController *)vc
// Trimming Code
- (id)initWithStyle:(UITableViewStyle)style
// Trimming Code
- (void)showInfo:(id)sender
// Create the contact view controller
ContactViewController *contactViewController = [[ContactViewController alloc] init];
if ([self splitViewController])
[self transferBarButtonToViewController:contactViewController];
UINavigationController *nvc = [[UINavigationController alloc]
initWithRootViewController:contactViewController];
// Create an array with our nav controller and this new VC's nav controller
NSArray *vcs = [NSArray arrayWithObjects:[self navigationController],
nvc,
nil];
// Grab a pointer to the split view controller
// and reset its view controllers array.
[[self splitViewController] setViewControllers:vcs];
// Make contact view controller the delegate of the split view controller
[[self splitViewController] setDelegate:contactViewController];
// If a row has been selected, deselect it so that a row
// is not selected when viewing the info
NSIndexPath *selectedRow = [[self tableView] indexPathForSelectedRow];
if (selectedRow)
[[self tableView] deselectRowAtIndexPath:selectedRow animated:YES];
else
[[self navigationController] pushViewController:contactViewController
animated:YES];
// Give the VC the channel object through the protocol message
// [channelViewController listViewController:self handleObject:channel];
- (void)viewDidLoad
// Trimming Code
- (NSInteger)tableView:(UITableView *)tableView
numberOfRowsInSection:(NSInteger)section
return [[channel items] count];
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath
// Trimming Code
- (void)fetchEntries
// Trimming Code
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
if (![self splitViewController])
[[self navigationController] pushViewController:detailViewController animated:YES];
else
[self transferBarButtonToViewController:detailViewController];
// We have to create a new navigation controller, as the old one
// was only retained by the split view controller and is now gone
UINavigationController *nav =
[[UINavigationController alloc] initWithRootViewController:detailViewController];
NSArray *vcs = [NSArray arrayWithObjects:[self navigationController],
nav,
nil];
[[self splitViewController] setViewControllers:vcs];
// Make the detail view controller the delegate of the split view controller
[[self splitViewController] setDelegate:detailViewController];
RSSItem *item = [[channel items] objectAtIndex:[indexPath row]];
// Next line reports: No visible @interface for 'DetailViewController' declares the selector 'listViewController:handleObject:'
[detailViewController listViewController:self handleObject:item];
@end
DetailViewController.h:
#import <UIKit/UIKit.h>
#import <Foundation/Foundation.h>
#import "ListViewController.h"
@class RSSItem;
@class Reachability;
@interface DetailViewController : UIViewController <ListViewControllerDelegate> // Cannot find protocol declaration for 'ListViewControllerDelegate'
__weak IBOutlet UILabel *nameField;
__weak IBOutlet UITextView *descriptField;
__weak IBOutlet UIImageView *imageView;
__weak IBOutlet UITextView *introtextField;
__weak IBOutlet UIButton *dsButton;
__weak IBOutlet UIButton *aeButton;
__weak IBOutlet UIButton *imButton;
-(BOOL)reachable;
@property (nonatomic, strong) RSSItem *item;
@property (nonatomic, strong) UIImage *productImage;
@end
DetailViewController.m:
#import "DetailViewController.h"
#import "RSSItem.h"
#import "RSSChannel.h"
#import "Reachability.h"
@interface DetailViewController ()
@end
@implementation DetailViewController
- (void)listViewController:(ListViewController *)lvc handleObject:(id)object
//RSSItem *item = object; //This was in the example code but if left in the next line reported "Local declaration of 'item' hides instance variable"
// Validate the RSSItem
if (![item isKindOfClass:[RSSItem class]])
return;
[self setItem:item];
[[self navigationItem] setTitle:[item name]];
[nameField setText:[item name]];
[descriptField setText:[item descript]];
[introtextField setText:[item introtext]];
@synthesize item;
- (BOOL)reachable
// Trimming Code
- (void)viewDidLoad
[super viewDidLoad];
[[self view] setBackgroundColor:[UIColor whiteColor]];
- (void)viewWillAppear:(BOOL)animated
if (item)
[super viewWillAppear:animated];
[nameField setText:[item name]];
[descriptField setText:[item descript]];
[introtextField setText:[item introtext]];
// Trimming Code (all the stuff that looks for this or that value and acts upon it)
else
// The following appears in the log:
NSLog(@"There's no item selected");
@end
【问题讨论】:
【参考方案1】:我认为你遇到了一个问题,编译器会因为有几个而感到困惑
#import "DetailViewController.h"
如果您从 ListViewController.h 中删除此导入并保留
@class DetailViewController;
那么我认为这将摆脱你的编译器问题。
您可能需要将< UISplitViewControllerDelegate >
添加到您的其他几个课程中。看起来您将它们设置为拆分视图上的委托,但未采用协议。
【讨论】:
谢谢,洛根! (请注意,此答案是我发布给自己的答案的来源,其中逐行更改。)【参考方案2】:委托关系没有 100% 正确设置。这是解决此问题的方法。
在 ListViewController.m 中,添加了一个类扩展:
@interface ListViewController() <UISplitViewControllerDelegate>
@end
在 ListViewController.h 中,删除:
#import "DetailViewController.h"
在 DetailViewController.h 中,将行改为:
@interface DetailViewController : UIViewController <ListViewControllerDelegate, UISplitViewControllerDelegate>
在 ContactViewController.h 中,将行改为:
@interface ContactViewController : UIViewController <MFMailComposeViewControllerDelegate, UISplitViewControllerDelegate>
这些东西清除了所有错误。正如我在原始帖子中所希望的那样,这并没有纠正我的项目未传递给 detailViewController 的问题,因为该问题是在 DetailViewController.m 的 handleObject 语句中使用“item”而不是“object”的结果。
【讨论】:
以上是关于UISplitView,在设置代表时接收语义问题的主要内容,如果未能解决你的问题,请参考以下文章