Big Nerd Ranch の iOS プログラミング ガイド (第 3 版) に従って、自社の製品のリストとそれぞれの詳細ビューを表示する Xcode プロジェクトをセットアップしました。
アプリは必要に応じて問題なく動作しましたが、ユーザー エクスペリエンスを向上させようとしたときに問題が発生し始めました。iPad 用の UISplitViewController を追加したことで、頭が痛くなり、午後が無駄になりました。
現在、デリゲート関連のコードでセマンティックの問題が報告されています。1 つは DetailViewController.h にあり、もう 1 つは ListViewController.m にあります。
投稿する前にこのコードの意図を要約しますが、経験が浅いため、いくつかの微妙な点を見逃す可能性があります。
AppDelegate は、UITableViewController (ListViewController クラス) と UIViewController (DetailViewController クラス) を割り当ててから、iPad をチェックします。iPad の場合、2 つのビューの配列を使用して UISplitViewController を作成します。それ以外の場合は、ListViewController をマスター ビューとして読み込みます。
2 つのビュー間の委任関係を作成しようとする前は、アプリは正常にビルドされていましたが、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
詳細ViewController.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