我如何“连接”视图控制器的表视图 [英] How do I "connect" a table view to a view controller

查看:142
本文介绍了我如何“连接”视图控制器的表视图的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

好吧,我知道这是一个模糊的概念问题,但我真的需要帮助。如果您决定花时间阅读本文,请提前致谢。我甚至都不会考虑写这么多,除非这是一个很棒的论坛,有这么多有用的人,我认为这是最好的地方。



这都是相关的这里的问题(你不必看它 - 我在下面解释一切):初始化表时传递参数



我已经在同样的问题上工作了几天,但我意识到必须有一些大的东西我我失踪了。我用google搜索和谷歌搜索,我甚至在几天前买了两本Obj-C书(并且大约有50%读过),但我仍然在抓住看起来应该非常容易的东西。我显然对OOP很新,但我在HTML,perl,sql,python以及一些像pascal和basic这样的古老东西中都有平庸的技巧。我是一个n00b,但不是白痴(好吧,实际上这种体验正在改变我的想法)。



无论如何,我的最终目标是简单地创建一个在第一个视图(级别1)上有8个普通按钮的应用程序,每个按钮基本上都做同样的事情 - 这是显示一个简单的表格视图(级别2),单元格中的数据可以单击以继续深入查看细节(第3级)。非常基本和直接的概念。 8个可能的2级之间的唯一区别是将显示的数据。我已经构建了sql查询,就像我想要的每个按钮一样。



所以,这就是我的立场:我有一个完美的应用程序,可以完成所有关卡2完全按照我的预期 - 查询工作,表格很漂亮 - 这太棒了。



此外,我还有另一个基于导航的应用程序在1级启动并显示8个按钮(我隐藏了1级的导航栏)。如果我单击级别1上的任何按钮,则级别2视图(导航栏+表格)将完全按照我的要求滑入视图。问题是表格只是空白。无论我做什么,我都无法在第二个应用程序中获得级别2来向我显示数据,即使我可以在第一个应用程序中完美地显示所有数据。对于我的生活,我无法弄清楚如何将第1级与第2级链接。



希望你能理解这个差距,我正试图弥合。由于第2级有8种可能性(在同一个sql表上的sql查询只有很小的差异),我最初尝试了一种传递整数到2级视图的方式(在第一个应用程序中)和然后根据传递的内容选择sql查询(参见上面关于该惨败的链接)。一旦我开始工作,我计划弄清楚如何使按钮稍后通过。但是,经过大约16个小时的拧紧,我就放弃了,决定制作8个不同的表视图控制器,除查询外,所有代码都几乎相同。这样一来,如果我只能在第1级获得一个SINGLE按钮,只需按下没有参数的2级中的一个,我就会成为一个可怕但成功的程序员。



不幸的是,即便如此,对我来说也没有用。我已经尝试了在Interface Builder中可以想到的所有可能的控制 - 拖动和窗口/视图/表组合,但无论我尝试什么,数据都不会加载到表视图中,即使它在我的第一个应用程序中运行良好。我已经完成了每一行代码 - 它们是相同的,除了必须调用或启动2级部分,我只是没有得到它。



<那么,我将在这里打破常规/期望,而不是在我的问题中发布任何代码。我只是想知道 - 这怎么可能这么难?我非常注重分析,而且很快就会流行起来,但我不得不说我生活中的技术挑战从未如此谦卑。



任何人都可以向我解释在概念层面,我需要在这里做什么或者我缺少什么?即使你给我一些阅读内容的链接,我也会非常感激。我在youtube上看了几十个小时的教程,但是我总是更多。



当然我愿意分享我的代码,但是有这样的大部分内容我在这方面很新,我真的不知道相关部分在哪里。另外,我实际上想了解所有这些是如何工作的,所以我可以帮助别人。如果在这里有PM这样的东西,如果你愿意看看,我会给你发电子邮件。一旦我开始工作,我将在这里发布代码。我不得不相信还有其他人在寻找和我一样的东西。但是,更重要的是,我只是想从高层次了解解决问题的正确方法是什么?如果你查看我的链接,你可以看到我一直在尝试(这是将一个整数传递给填充表格的方法),但正如我所说,我基本上放弃了,因为我没有得到任何地方。人们正试图帮助我,但我是个白痴。



感谢我带着令人痛苦的长信息。如果你做到这一点,并为我提出一些建议,我会全力以赴。不过我会说实话 - 如果你告诉我,我应该废弃整件事并使用核心数据我会哭。我真的不认为我有时间找出一种完全不同的数据管理方式。正如我所说,我对数据库和我的应用程序的查询部分非常满意 - 它只是管理怪异的视图并在它们之间传递数据,这让我感到害怕!



感谢任何帮助 - 非常感谢你们。

解决方案

如果我理解你的问题,你会问如何初始化视图控制器并传入一些数据以改变其行为。这里要理解的关键概念是如何在Objective-C中初始化对象。 iOS新手开发人员最常见的问题之一是:


如何 可以 通过 数据 我的之间视图


是的,那里有八个不同的链接。 (好吧,第八个链接有点偏离主题,但它足够接近。)有几种方法可以做到这一点,我将简要介绍它们。我还将描述自定义初始值设定项,这也是一个相关点。



让我们假设我们正在构建一个目录应用程序,它显示了各种类别的产品。想象一下,我们的应用程序打开了一个产品列表,就像Apple Store App一样。假设当用户点击产品时我们想要显示产品页面。


  1. 您可以设置属性下一个视图控制器。 - 简单地说,我们可以创建一个 UIViewController 子类并设置 productID 财产(我们编造)。让我们调用新的 UIViewController a ProductPageViewController 。以下是它的外观:

       - (void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath 

    //创建ProductPageViewController
    ProductPageViewController * PPVC = [[ProductPageViewController的alloc] initWithNibName:@ ProductPageViewController 束:无];
    //在我们的ProductPageViewController上设置属性
    [ppvc setProductID:42];
    //我们通常会在这里展示PPVC。
    //演示后,请记得发布视图控制器
    }

    In第一行,我们创建产品视图控制器。我们调用 alloc ,然后 init 。 (函数被包装 - 也就是说,我们直接在 alloc 方法的结果上调用 init 。)



    然后,我们设置视图的属性。该视图现在可以在 viewWillAppear 中配置,一切正常。


  2. 您可以分享数据通过持久存储。 - 此方法的工作方式略有不同。视图控制器根本不进行通信,除了第一个呈现第二个控制器。只要第一个视图中的值发生更改(您希望保留),就可以将其写入Core Data或 NSUserDefaults 。然后,新视图会根据需要读取值。



    在您的第一个视图控制器中:

      //存储数据
    A方法 - (无效)storeData:(ID)的pageID {
    [[NSUserDefaults的的setObject:的pageID forKey:@ 的pageID];
    }

    - (void)showNewPPVC {

    ProductPageViewController * ppvc = [[ProductPageViewController alloc] initWithNibName:@ProductPageViewControllerbundle:nil];
    //显示然后发布PPVC
    }


  3. 您可以使用自定义初始化程序。 - 一旦您理解了这个概念,这可能是最直观的方法,因为这是唯一一个实际传递数据的方法。 (与没有数据直接共享的方法2和数据作为属性传递的方法1相反。)



    请注意,在前面的示例中,我使用了 initWithNibName:Bundle 方法。您可能还注意到 UITableViewController 使用不同的初始化程序, initWithStyle:。这两个初始化器接收新对象的一些信息,以便它知道如何加载。让我们来看看第一个第一:

       - (ID)initWithNibName:(的NSString *)nibNameOrNil软件包:(一个NSBundle *)bundleNameOrNil ; 

    第一个参数告诉视图控制器加载哪个nib文件。我现在要忽略第二个参数,因为除了 nil 之外,我从未见过传入任何内容。向右移动到第二个例子:

       - (id)initWithStyle:(UITableViewStyle)样式; 

    您可以传递两个 UITableViewStyle 中的一个>价值观。这是定义表视图样式的一种方法(另一种方法是直接修改nib文件)。



    让我们将这个概念扩展到我们的示例。我现在要向您展示如何制作自己的自定义初始化程序。让我们初始化我们的ProductPageViewController实例:

       - (id)initWithProductID:(int)productID; 

    这很简单。现在,我们需要实现该方法,并实际使用产品ID执行某些操作。我们将从这里的准系统代码开始,需要模仿默认初始化程序的功能。

       - (id) initWithProductID:(int)productID {
    self = [super init];

    返回自我;
    }

    此方法将返回我们的 ProductPageViewController的初始化副本但是,它还不会从NIB加载我们的UI,或者如果这是 UITableViewController ,它就不会设置 UITableViewStyle 。让我们首先使用NIB,然后我将展示如何使用 UITableViewController 。所以......

       - (id)initWithProductID:(int)productID {
    self = [super initWithNibName:@ ProductPageViewControllerBundle:nil];

    返回自我;
    }

    现在。我们有一个初始化的 ProductPageViewController ,从NIB加载,但它还没有做任何事情。请注意我们如何不公开 NibName Bundle 参数,但我们只是自己传递它们。如果你愿意,你理论上也可以揭露它们。现在,让我们拿一下 productID 并用它做点什么。

       - (id)initWithProductID:(int)productID {
    self = [super initWithNibName:@ProductPageViewControllerBundle:nil];

    if(self){
    self.prodID = productID;
    }

    返回自我;
    }

    通过我们的最新更改,我们的 PPVC 现在知道 productID 。它可以根据需要查询数据库并对结果执行操作。然后,您可以根据此 productID 运行不同的查询。


另外两个快速提示:


  1. 也许你想传递几个参数。当然你也可以简单地将它们添加到他们的方法签名 - (ID)initWithProductID:(INT)的productID andCategoryID(INT)的categoryID ,但如果你有会发生什么五,六,或五十六(是的,那是很多)的论点?我建议传入一个集合或一组参数。


  2. 要使用带有 UITableView 的自定义初始化程序,您传入 UITableViewStyle 而不是NIB名称。以下是它的外观:

       - (id)initWithProductID:(int)productID {
    self = [super initWithStyle:UITableViewStyleGrouped];

    if(self){
    self.prodID = productID;
    }

    返回自我;
    }


制作小节时,我建议持久数据和自定义初始化器的组合。我还建议您查看 viewDidLoad viewWillAppear 方法。


Alright, I know this is a vague conceptual question, but I really need help here. Thanks in advance if you decide to take the time to read this. I would never even consider writing this much except this is such a great forum with so many helpful people I thought this would be the best place to ask.

This is all related to the question here (you don't have to look at it - I explain everything below): Pass parameter when initializing table

I've been working for days on the same problem, but I'm realizing there must be something big I'm missing. I've googled and googled and I even bought (and about 50% read) two Obj-C books a few days ago, but I'm still grasping at something that seems like it should be incredibly easy. I'm obviously pretty new to OOP, but I have mediocre skills in HTML, perl, sql, python as well as some of the ancient stuff like pascal and basic. I'm a n00b, but not a moron (well, actually this experience is changing my mind a bit).

Anyway, my end goal here is to simply create an app with 8 "normal" buttons on the first view (level 1), each doing basically does the same thing - which is to show a simple table view (level 2) with data in cells that can be clicked to continue to drill down to details (level 3). Very basic and straightforward concept. The only difference between the 8 possible level 2's is the data that will be shown. I've already constructed sql queries that work just as I want for each button.

So, here's where I stand: I have a perfectly working app that does everything from level 2 down exactly as I expect - the queries work, the tables are beautiful - so that's great.

Also, I have another nav-based app that launches on "level 1" and shows me 8 buttons (I hide the nav bar on level 1). If I click any of the buttons on level 1, the level 2 view (which is a nav bar + a table) slides into view exactly like I want. The problem is the table is just blank. No matter what I do, I can't get the level 2 in the second app to show me the data, even though I can show all of that data in the first app perfectly. For the life of me, I can't figure out how to "link" level 1 with level 2.

Hopefully you can understand this gap I'm trying to bridge. Since there are 8 possibilities for level 2 (with only very slight differences in sql queries on the same sql table), I initially tried coming up with a way of "passing" an integer to the level 2 view (in the first app) and then selecting the sql query based on what was passed (see the link above for that fiasco). Once I got that working, I planned to figure out how to make the buttons do the "passing" later. However, after about 16 hours screwing with that, I just gave up and decided to make 8 different table view controllers, all with nearly identical code except the query. That way, if I could just get a SINGLE button on level 1 to simply push to just ONE of the level 2's with NO parameters I would be a horrible but successful programmer.

Unfortunately, even that hasn't worked out for me. I have tried every possible control-drag and window/view/table combination I can think of in Interface Builder, but no matter what I try, the data never loads into the table view, even though it works great in my first app. I have gone through every line of code - they are the same except something has to "call" or "launch" the level 2 part and I'm just not getting it.

So, I'm going to break with convention/expectations here and not post any code in my question. I just want to know - how can this possibly be so difficult?? I am very analytically minded and I catch on quickly, but I have to say I have never been so humbled by a technical challenge in my life.

Can anyone explain to me, at a conceptual level, what I need to be doing here or what I'm missing? Even if you give me a link to something to read I would appreciate it very much. I have watched tens of hours of tutorials on youtube, but I'm always up for more.

Of course I'm willing to share my code, but there is so much of it and I'm so new at this I really don't know where the relevant parts are. Plus, I actually want to learn how all of this works so I can help others. If there is such a thing as PM on here I'll email it to you if you're willing to take a look. Once I get it working, I will post the code here. I have to believe there are other people looking for the same kind of thing as I am. However, more importantly, I just want to know, from a high level, what is the correct way to approach my problem? If you look at my link you can see what I've been trying (which was to pass an integer to the method that populates the table), but as I said, I basically gave up on that because I wasn't getting anywhere. People are trying to help me, but I'm an idiot.

Thanks for bearing with my agonizingly long message. If you made it this far and have some suggestions for me I'm all ears. I'll be honest, though - if you tell me I should just scrap the whole thing and use core data I'll cry. I really don't think I have the time to figure out a whole different way of managing data. As I said, I'm pretty happy with the database and the query parts of my app - it's just managing the freaking views and passing data between them that is killing me!

Any help is appreciated - thank you all so much.

解决方案

If I understand your question correctly, you are asking how to initialize a view controller and pass in some data to alter its behavior. The key concept here to understand is how objects are initialized in Objective-C. One of the most common questions that developers who are new to iOS have is:

How can I pass data between my views?

Yes, eight different links there. (Okay, that eighth link is a little bit off topic, but it's close enough.) There are several ways of doing this and I'll go through them briefly. I'll also describe custom initializers, which are a relevant point as well.

Let's pretend we were building a catalog application which shows a bunch of products in various categories. Imagine that our app opens to a list of products, much like the Apple Store App. Say that when the user taps on a product we want to show a product page.

  1. You can set properties on the "next" view controller. - Simply, we can create a UIViewController subclass and set the productID property (which we made up). Let's call our new UIViewController a ProductPageViewController. Here's how this would look:

    - (void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath
    
      //Create a ProductPageViewController
      ProductPageViewController *ppvc = [[ProductPageViewController alloc] initWithNibName:@"ProductPageViewController" bundle:nil];
      //set the property on our ProductPageViewController
      [ppvc setProductID:42];
      //We would usually present the PPVC here.
      //After presenting, remember to release the view controller
    }
    

    In the first line, we create the product view controller. We call alloc, then init. (The functions are wrapped - that is, we call init directly on the result of the alloc method.)

    Then, we set a property of our view. The view can now be configured in viewWillAppear and all is well.

  2. You can share the data through a persistent store. - This method works a little differently. The view controllers don't communicate at all, except for the first one presenting a second one. Whenever a value in the first view changes (that you want to persist), you write it to Core Data or NSUserDefaults. Then, the new view reads the value as it needs it.

    In your first view controller:

    //A method to store the data
    - (void)storeData:(id)pageID{
        [[NSUserDefaults setObject:pageID forKey:@"pageID"];
    }
    
    - (void)showNewPPVC{
    
      ProductPageViewController *ppvc = [[ProductPageViewController alloc] initWithNibName:@"ProductPageViewController" bundle:nil];        
      //Show and then release the PPVC
    }
    

  3. You can use custom initializers. - This is probably the most intuitive way to do it, once you understand the concept, because this is the only one where data is actually "passed". (As opposed to method 2 where no data is directly shared and method 1 where data is passed as a property.)

    Notice that in the earlier examples, I used the initWithNibName:Bundle method. You might also notice that UITableViewControllers use a different initializer, initWithStyle:. Those two initializers take in some information for the new object so that it knows how to load. Let's look at the first one first:

    - (id)initWithNibName:(NSString *)nibNameOrNil Bundle:(NSBundle *)bundleNameOrNil;
    

    The first argument tells the view controller which nib file to load up. I'm going to ignore the second argument for now, since I've never seen anything passed in except nil. Moving right along to the second example:

    - (id)initWithStyle:(UITableViewStyle)style;
    

    You can pass in one of two UITableViewStyle values here. This is one way to define the style of a table view (the other way being to modify a nib file directly).

    Let's extend this concept a bit to our example. I'm now going to show you how to make your own custom initializer. Let's initialize our ProductPageViewController instance:

    - (id) initWithProductID:(int)productID;
    

    That's simple enough. Now, we need to implement the method and actually do something with the product ID. We'll start with the barebones code here, required to "mimic" the functionality of the default initializer.

    - (id) initWithProductID:(int)productID{
     self = [super init];
    
     return self;
    }
    

    This method will return an initialized copy of our ProductPageViewController, however, it won't load up our UI from a NIB yet, or if this were a UITableViewController, it wouldn't set the UITableViewStyle. Let's work with a NIB first and then I'll show how to work a UITableViewController. So...

    - (id) initWithProductID:(int)productID{
     self = [super initWithNibName:@"ProductPageViewController" Bundle:nil];
    
     return self;
    }
    

    Now. we have an initialized ProductPageViewController, loaded from a NIB, but it doesn't do anything yet. Notice how we don't expose the NibName and Bundle arguments, but we just pass them in ourselves. If you want, you could theoretically expose those too. Now, let's take that productID and do something with it.

    - (id) initWithProductID:(int)productID{
     self = [super initWithNibName:@"ProductPageViewController" Bundle:nil];
    
       if(self){
         self.prodID = productID;
       }
    
     return self;
    }
    

    With our latest changes, our "PPVC" now knows about the productID. It can query the database as you want and do things with the results. You can then run different queries based on this productID.

Two More Quick Tips:

  1. Perhaps you want to pass in several arguments. Of course you can simply add them to them method signature - (id) initWithProductID:(int)productID andCategoryID(int)categoryID, but what happens if you have five, six, or fifty six (yea, that's a lot) arguments? I'd advise passing in a collection or array of arguments.

  2. To use custom initializers with UITableView, you pass in a UITableViewStyle instead of a NIB name. Here's what it might look like:

          - (id) initWithProductID:(int)productID{
            self = [super initWithStyle:UITableViewStyleGrouped];
    
            if(self){
              self.prodID = productID;
            }
    
            return self;
          }
    

When making your subsections, I'd suggest a combination of persistent data and custom initializers. I also advise taking a peek at the viewDidLoad and viewWillAppear methods.

这篇关于我如何“连接”视图控制器的表视图的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆