不在UITableViewController中的UItableView上的奇怪行为

时间:2015-12-20 11:58:22

标签: ios swift uitableview

我有一个UIViewController,当用户点击一个按钮时,我想显示一个UITableView。我从服务器收到数据。

问题在于发生了一些奇怪的事情。有时,并非所有单元格都会更新。换句话说,在我的原型单元格中,有两个按钮,默认文本,但是当我从服务器加载数据时,不是所有按钮文本都更新,而是当我滚动表格时,它们变为更新。 同样当我滚动*表格时,有时按钮会返回默认文字。

以下是我的代码:(非常简单)

class CusinePreferencesTableView: NSObject, UITableViewDelegate, UITableViewDataSource {

    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCellWithIdentifier(CellIdentefiers.oneCusinePreferencesCell.rawValue, forIndexPath: indexPath) as! OneCusinePreferencesTableViewCell
        var row = indexPath.row
        print("row = \(row)")
        let oneCusineDataLeft = Preferences2ViewController.cusines![row]
        cell.leftButton.titleLabel?.text = oneCusineDataLeft
        row = row + 1
        if row < Preferences2ViewController.cusines!.count{
            let oneCusineDataRight = Preferences2ViewController.cusines![row]
            cell.rightButton.titleLabel?.text = oneCusineDataRight
        }else {
            //I should hide the right button
        }
        return cell
    }

    func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        if let cusines = Preferences2ViewController.cusines {
            if cusines.count % 2 == 0 {
                return cusines.count/2
            }else {
                var count = cusines.count/2
                count = count + 1
                return count
            }
        }else {
            return 0
        }
    }

    func numberOfSectionsInTableView(tableView: UITableView) -> Int {
        return 1
    }

}

这是表视图(如果你想要的话) enter image description here

如果您发现自己没有得到问题描述,我可以为您制作视频

更新1

我已经调用了reloadData,就像你在这里看到的那样(我从服务器获取数据)

 func loadCusiens(){
        let url = NSURL(string: ConstantData.getWebserviceFullAddress()+"preferences/cusines")
        let request = NSMutableURLRequest(URL: url!)
        request.HTTPMethod = "POST"
        let session = NSURLSession.sharedSession()
        let task = session.dataTaskWithRequest(request, completionHandler: {(data, response, error ) in
            if let error = error {
                print("error = \(error)")
            }

            if let data = data {
                do{
                    let jsonArray = try NSJSONSerialization.JSONObjectWithData(data, options: []) as! NSArray
                    var results = [String]()
                    for oneJSON in jsonArray {
                        let name = oneJSON["name"] as! String
                        results.append(name)
                    }
                    dispatch_async(dispatch_get_main_queue(), {
                        Preferences2ViewController.cusines = results
                        self.cusineTableView.reloadData()
                    })
                } catch{
                    print("This exception happened = \(error)")
                }
            }
        })
        task.resume()
    }

更新

现在在else部分,我将右键的文本设置为&#34; sometext&#34; 这是关于问题的视频

http://www.mediafire.com/watch/k2113ovebdvj46d/IMG_0911.MOV

3 个答案:

答案 0 :(得分:1)

看起来像是重用问题。基本上,如果您按照Apple和其他地方的示例进行操作,它会使用出列函数。这意味着iOS将查找已经不再显示的现有单元格,并为您提供绘制新单元格内容的单元格。但是当然如果旧电池有一堆东西,你会看到旧的东西。解决方案是始终将所有内容分配给正确的新值。

如果您的单元格具有可变信息,这可以让您轻松获得,例如,如果某个条目设置了您设置的图片,但是如果它没有,则不会设置。然后会发生什么事情,当你得到一个没有图片的条目时你的代码可能没有将图像设置为nil,你就会看到一个滚动的旧单元格的图片。

答案 1 :(得分:1)

请让我解释一下UITableViewCells作品的重复使用

假设你有一个非常庞大的细胞,你只能在屏幕上看到3个细胞。 现在假设您在屏幕上看到以下单元格:

A
B
C

在屏幕上......您的数据源为:A B C C B A

现在你正在向下滚动1个单元格:

因此,单元格A从Up(它是第一个单元格)向下并成为您最后一个可见单元格

所以现在在屏幕上你会看到

B
C
A   // While you want to draw a cell `C` here according to the dataSource

cellForRowAtIndexPath...

现在发生了什么

您从头开始获得相同的单元格A

假设您的单元格A只有1个按钮,而单元格C需要显示2个按钮 因为您已经绘制了单元格A,所以您使用1个按钮绘制它(假设您将右侧按钮隐藏属性设置为YES)。

现在你想在重用的单元格C上绘制单元格A (假设你为细胞类型设置了TAGS,以便知道在cellForRowAtIndexPath中弹出了哪种类型的细胞)

现在您可以查询单元格的标签

if(myCell.tag == `A`/*(Assume you have an Enum for tags)*/)
{
    //So here you will want to Unhide the Right button of the cell (which is currently still cell A
    //After you have done with all needed adjustments you will want to set the appropriate tag for this cell to be ready for the next reuse -> so set it's tag to C
    //Now next time this cell will get reused it will be drawn as cell `C` and it will think it is a cell `C`  
}

答案 2 :(得分:1)

<强>更新

主要问题不是单元重用,也不是我在下面解释的布局问题,而是使用:

<android.support.design.widget.AppBarLayout
    android:id="@+id/app_bar"
    android:layout_width="match_parent"
    android:layout_height="@dimen/app_bar_height"
    android:fitsSystemWindows="true"
    android:theme="@style/HeyVolo.AppBarOverlay">

    <android.support.design.widget.CollapsingToolbarLayout
        android:id="@+id/toolbar_layout"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:fitsSystemWindows="true"
        app:contentScrim="@color/darkblue"
        app:layout_scrollFlags="scroll|exitUntilCollapsed">

        <ImageView
            android:id="@+id/main.backdrop"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:scaleType="centerCrop"
            android:fitsSystemWindows="true"
            android:src="@drawable/peace"
            app:layout_collapseMode="parallax"

            />



    </android.support.design.widget.CollapsingToolbarLayout>
</android.support.design.widget.AppBarLayout>



<android.support.v4.widget.NestedScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:layout_behavior="@string/appbar_scrolling_view_behavior"
    >


    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_margin="@dimen/text_margin"
        android:id="@+id/eventDescriptionText"
        android:text="" />

</android.support.v4.widget.NestedScrollView>

<android.support.design.widget.FloatingActionButton
    android:id="@+id/fab"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_margin="@dimen/fab_margin"
    android:src="@drawable/ic_assignment_turned_in_24dp"
    app:layout_anchor="@id/app_bar"
    app:layout_anchorGravity="bottom|end" />

设置按钮文字。你必须使用:

cell.leftButton.titleLabel?.text = oneCusineDataLeft

代替。 (实质上,cell.leftButton.setTitle(oneCusineDataLeft, forState: .Normal) 会跟踪标题文本在处于不同的状态时应显示的状态&#34; - 正常,选定等。虽然您的代码更改了当前显示的文本,一旦按钮改变状态,它就会将文本设置回存储的值。我假设按钮状态在显示单元格时被重置。UIButton方法更新存储的值。)

<强>原始

抛开细胞重用问题,我不认为你的代码会达到你想要的效果。按照目前的编码,布局将是这样的:

setTitle

我猜你真的想要这个:

Row 0: left: cuisine 0, right: cuisine 1 
Row 1: left: cuisine 1, right: cuisine 2 
Row 2: left: cuisine 2, right: cuisine 3

如果是这种情况,请按如下方式修改您的代码:

Row 0: left: cuisine 0, right: cuisine 1
Row 1: left: cuisine 2, right: cuisine 3
Row 2: left: cuisine 4, right: cuisine 5

我还应该注意,使用func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCellWithIdentifier(CellIdentefiers.oneCusinePreferencesCell.rawValue, forIndexPath: indexPath) as! OneCusinePreferencesTableViewCell var row = indexPath.row print("row = \(row)") let oneCusineDataLeft = Preferences2ViewController.cusines![2*row] cell.leftButton.titleLabel?.text = oneCusineDataLeft if (2*row+1) < Preferences2ViewController.cusines!.count{ let oneCusineDataRight = Preferences2ViewController.cusines![2*row+1] cell.rightButton.titleLabel?.text = oneCusineDataRight }else { //I should hide the right button cell.rightButton.titleLabel?.text = "" } return cell } func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { if let cusines = Preferences2ViewController.cusines { if cusines.count % 2 == 0 { return cusines.count/2 }else { return (cusines.count+1)/2 } }else { return 0 } } 而不是UICollectionView可能会更好,因为前者将更容易和直观地提供多列流。