130

I have some strange issue with UITableView only in iOS 7.

UITableViewCellSeparator disappears above the first row and below the last row. Sometimes after selecting the rows or some scrolling actions it appears.

In my case tableView is loaded from the Storyboard with UITableViewStylePlain style. The problem is surely not in UITableViewCellSeparatorStyle, which is not changed from default UITableViewCellSeparatorStyleSingleLine.

As I read at Apple Dev Forums (here and here) other people have such problem and some workarounds are found, for example:

Workaround: disable the default selection and recreate the behaviour in a method
trigged by a tapGestureRecognizer.

But I am still searching for the reason of such separator strange behaviour.

Any ideas?

Update: As I saw in XCode 5.1 DP and iOS 7.1 beta, Apple tried to fix this problem. Now separator is shown as needed sometimes below the last row, after some refreshing, but not after tableview creation.

Ortwin Gentz
  • 52,648
  • 24
  • 135
  • 213
B.S.
  • 21,660
  • 14
  • 87
  • 109
  • 19
    Sometimes I feel like iOS7 is so immature. This and the long list of things that I have here show how far iOS7 is from perfection of previous iOSs. – Bms270 Sep 26 '13 at 19:52
  • 1
    The Settings app by Apple has the same problem, so I believe this is an iOS 7 issue. I have reported it, and in their followup they asked for images showing the issue. – Johan Oct 03 '13 at 22:54
  • @Gatada Where in the Settings app are you seeing the issue? – Jamie Forrest Oct 28 '13 at 19:32
  • My issue occurs when the table begins editing (cell content shifts right and red circles appear) the separators vanish. I've tried all the suggestions listed at the time of this positing and none work for me. I just downloaded 7.0.4 and still have the issue. I have one device running 7.0.2 and have no issues with separators at all (same build of my code). My 7.0.2 device is non Retina and my 7.0.3/7.0.4 device is Retina, so it could be related to the screen scale and not the iOS build. – Swany Nov 14 '13 at 20:19
  • Digging deeper, using Reveal App I was able to "tweak" the UITableView separator style at runtime (from singleLine to none, then back to singleLine) and the missing separators reappear. So it definitely appears to be a draw order thing, which seems right given some of the workarounds that others have used to get around this issue. – Swany Nov 14 '13 at 20:20
  • My tableView row height is 60 in the NIB (I've tried using 60.0 by overriding tableView: heightForRowAtIndex:). Using Reveal I can see that on the iOS 7.0.2/non retina device my cell content size gets forced by the OS to 59.0 and the OS's internal separatorView is located at 59.5 with a height of 0.5. On iOS 7.0.4/retina device my cell content size is forced to 59.5 and the separatorView is located at 59.75 with a height of 0.5. – Swany Nov 14 '13 at 20:20
  • Encountered the same issue and fixed by adding the following line in - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath – Ayesha Fatima Dec 11 '13 at 09:54
  • 2
    Encountered the same issue and fixed by adding [cell setSeparatorInset:UIEdgeInsetsFromString(@"1")]; with in (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath method – Ayesha Fatima Dec 11 '13 at 09:58
  • Happened to me when I set the selectionStyle of the cells to "None". I just disabled selection on the whole table and that worked for me as an interim solution. – Arjun Mehta Mar 26 '14 at 22:15
  • Adding an empty footer view also seems to be a workaround. Like that : `tableView.tableFooterView = [UIView new];` – nverinaud Mar 27 '14 at 09:15
  • 1
    This still appears to be broken in the iOS 8.0 betas. I've opened radar 17724043 should anyone care to dup it. – Andy Wilkinson Jul 18 '14 at 10:38
  • Please check this answer it solve this issue https://stackoverflow.com/a/56341369/8201581 – Yogesh Patel May 28 '19 at 11:38

37 Answers37

77

I dumped the subview hierarchy of affected cells and found that the _UITableViewCellSeparatorView was set to hidden. No wonder it's not shown!

I overrode layoutSubviews in my UITableViewCell subclass and now the separators are displayed reliably:

Objective-C:

- (void)layoutSubviews {
    [super layoutSubviews];

    for (UIView *subview in self.contentView.superview.subviews) {
        if ([NSStringFromClass(subview.class) hasSuffix:@"SeparatorView"]) {
            subview.hidden = NO;
        }
    }
}

Swift:

override func layoutSubviews() {
    super.layoutSubviews()

    guard let superview = contentView.superview else {
        return
    }
    for subview in superview.subviews {
        if String(subview.dynamicType).hasSuffix("SeparatorView") {
            subview.hidden = false
        }
    }
}

The other solutions proposed here didn't work consistently for me or seem clunky (adding custom 1 px footer views).

Andrey Gordeev
  • 30,606
  • 13
  • 135
  • 162
Ortwin Gentz
  • 52,648
  • 24
  • 135
  • 213
  • I have used your method but not in subclass I had added a category to UITableViewCell. It helped me. Thanks. – Vitalii Boiarskyi Jul 02 '14 at 07:25
  • Of course it's also possible in a category. Since this requires method swizzling, I went for the simple subclass approach. – Ortwin Gentz Jul 02 '14 at 11:20
  • 3
    This is the only solution that worked for me. My problem popped up whe the UITableView had enough rows to be scrollable. That "hasSuffix:" part is quite fragile though. – juhan_h Jul 23 '14 at 08:57
  • Works for me. Maybe question is silly, but isn't this using of Private API ? – Foriger Mar 31 '15 at 15:07
  • Technically it's not using private API and your app won't be rejected because of this. It relies on an implementation detail though and could break in a future iOS version. – Ortwin Gentz Apr 01 '15 at 08:07
  • @Foriger if you worry of using **hasSuffix:@"SeparatorView"**, try to replace it with **if(CGRectGetHeight(subview.frame) < 1.1)**. It probably even would work faster whether you don't use any other 1px custom views in your cell. I chose 1.1px 'cos in Retina UITableViewSeparator has 0.5 points height, but for non-Retina it could be 1.0. – David May 09 '15 at 17:40
  • Works for me, grouped UITableView (iOS 7 and iOS8). – Alex Sfinx87 Jun 23 '15 at 11:23
  • Although this mostly fixed the problem for me, for some reason one of my separators was still disappearing. Combining this fix with the toggling of `tableView.separatorStyle` suggested in other answers (which by itself made no difference for me) made it work for all of the separators. – Dan Dyer Nov 03 '15 at 13:14
42

This worked for me:

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {

    // fix for separators bug in iOS 7
    self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
    self.tableView.separatorStyle = UITableViewCellSeparatorStyleSingleLine;
samvermette
  • 40,269
  • 27
  • 112
  • 144
  • You deserve more up votes, this is exactly what I needed, I added it in a category, so now after I do [tableView reloadData], if this bug happens (in my case the footer separator that was hidden is reappearing), I call [tableView reloadSeparators]; – NiñoScript Apr 05 '14 at 04:56
12

I also had the problem with missing separator and I found out that the problem only occured when heightForRowAtIndexPath was returning a decimal number. Solution:

override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
    return ceil(yourHeight) // Ceiling this value fixes disappearing separators
}
Robert
  • 1,936
  • 27
  • 38
Emelie
  • 129
  • 2
  • 1
    What about the case if I do not implement even heightForRowAtIndexPath method? – B.S. Oct 02 '13 at 08:56
  • Interesting. However, it happens in my project as well - and heightForRowAtIndexPath isn't implemented. In IB row/cell height is 100. – Johan Oct 03 '13 at 22:58
  • 6
    It did not solve the issue for me and I do have the heightForRowAtIndexPath method. – Gergely Kovacs Oct 13 '13 at 08:21
  • Solves the issue at least partially. The cell does seem to be confused about non-integer heights. – Nick Frolov Oct 17 '13 at 08:43
  • You need to ceil the number of pixels and then divide by screen scale factor to get points which is okay to be in decimal. If you don't do this, it won't be retina optimized. – trss Mar 11 '14 at 16:38
11

Did you try adding a UIView of height 1 in the header and the footer of the table with light gray background color? Basically it'll mock the first and last separators.

airpaulg
  • 565
  • 3
  • 13
8

@samvermette

I fixed the problem by using this delegate methods. Now it doesn't flicker:

-(void)tableView:(UITableView *)tableView didHighlightRowAtIndexPath:(NSIndexPath *)indexPath {
    // fix for separators bug in iOS 7
    tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
    tableView.separatorStyle = UITableViewCellSeparatorStyleSingleLine;
}


-(void)tableView:(UITableView *)tableView didUnhighlightRowAtIndexPath:(NSIndexPath *)indexPath {
    // fix for separators bug in iOS 7
    tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
    tableView.separatorStyle = UITableViewCellSeparatorStyleSingleLine;
}
7

We encountered this issue in our app. When the user selected a cell, a new table view was pushed onto the navigation controller stack and then when the user popped it off, the separator was missing. We solved it by putting [self.tableView deselectRowAtIndexPath:indexPath animated:NO]; in the didSelectRowAtIndexPath table view delegate method.

wrightak
  • 646
  • 4
  • 7
6

Here is an easier (although a bit messy) workaround if you need one, try selecting and deselecting the cell after the data is reloaded and the default animation is done.

just add:

[self.tableView selectRowAtIndexPath:indexPath animated:NO scrollPosition:UITableViewScrollPositionNone];
[self.tableView deselectRowAtIndexPath:indexPath animated:NO];
redmoon7777
  • 4,498
  • 1
  • 24
  • 26
  • 1
    This workaround fixed it for me; however, I reversed it - to retain the selection. So, first deselect, then re-select. – Johan Oct 03 '13 at 23:03
  • 2
    I don't know what to override when you say "after the data is reloaded" – airpaulg Oct 28 '13 at 21:06
6

I've found that the easiest solution is to, after reloading a cell, also reload the cell above:

if (indexPath.row > 0) {
    NSIndexPath *path = [NSIndexPath indexPathForRow:indexPath.row - 1 inSection:indexPath.section];
    [self.tableView reloadRowsAtIndexPaths:@[path] withRowAnimation:UITableViewRowAnimationNone];
}
conmulligan
  • 7,038
  • 6
  • 33
  • 44
  • 1
    Worked for me. Thanks. Any other methods didn't help me (include separator style change from samvermette's answer). – surfrider Jun 11 '14 at 14:37
4

A simple and clean solution that works on both iOS 8 and iOS 9 (beta 1)

Here is a simple, clean and non-intrusive workaround. It involves calling a category method that will fix the separators.

All you need to do is to walk down the hierarchy of the cell and un-hide the separator. Like this:

for (UIView *subview in cell.contentView.superview.subviews) {
    if ([NSStringFromClass(subview.class) hasSuffix:@"SeparatorView"]) {
        subview.hidden = NO;
    }
}

What I recommend is to add this to a category on UITableViewCell, like this:

@interface UITableViewCell (fixSeparator)
- (void)fixSeparator;
@end

@implementation UITableViewCell (fixSeparator)

- (void)fixSeparator {
    for (UIView *subview in self.contentView.superview.subviews) {
        if ([NSStringFromClass(subview.class) hasSuffix:@"SeparatorView"]) {
            subview.hidden = NO;
        }
    }
}

@end

Because the separator can disappear in different cell than the one currently selected, it's probably a good idea to call this fix on all cells in the table view. For that, you can add a category to UITableView that goes like this:

@implementation UITableView (fixSeparators)

- (void)fixSeparators {
    for (UITableViewCell *cell in self.visibleCells) {
        [cell fixSeparator];
    }
}

@end

With this in place, you can call -fixSeparatos on your tableView right after the action that causes them to disappear. In my case, it was after calling [tableView beginUpdates] and [tableView endUpdates].

As I stated at the beginning, I've tested this on both iOS 8 and iOS 9. I presume it will work even on iOS 7 but I don't have a way to try it there. As you are probably aware, this does fiddle with internals of the cell so it could stop working in some future release. And Apple could theoretically (0.001% chance) reject your app because of this, but I can't see how they could even find out what you are doing there (checking the suffix of a class can't be detected by static analyzers as something bad, IMO).

Community
  • 1
  • 1
Lukas Petr
  • 1,513
  • 16
  • 19
  • YES. This worked for me, after converting over to latest version of Swift. ++ for calling fixSeparators after every call to tableView.endUpdates(). – ObjectiveTC Aug 02 '15 at 10:28
  • 1
    I am glad this was helpful to you! I really believe this is the best solution, so hopefully more people will discover it. – Lukas Petr Aug 03 '15 at 12:44
4

Based on @ortwin-gentz's comment, this solution works for me in iOS 9.

func fixCellsSeparator() {

    // Loop through every cell in the tableview
    for cell: UITableViewCell in self.tableView.visibleCells {

        // Loop through every subview in the cell which its class is kind of SeparatorView
        for subview: UIView in (cell.contentView.superview?.subviews)!
            where NSStringFromClass(subview.classForCoder).hasSuffix("SeparatorView") {
                subview.hidden = false
        }
    }

}

(Swift code)

I use fixCellsSeparator() function after calling endUpdates() in some methods of my tableView, for example:

override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {

    //  Perform some stuff
    //  ...

    self.tableView.endUpdates()
    self.fixCellsSeparator()

}

I hope this solution will be helpfull for someone!

Carlos D. Álvaro
  • 561
  • 1
  • 6
  • 12
2

Complement to the answer of airpaulg.

So basically one has to implement two UITableDelegate methods. Here's my solution which works on both iOS7 and iOS6.

#define IS_OS_VERSION_7 (NSFoundationVersionNumber_iOS_6_1 < floor(NSFoundationVersionNumber))

#define UIColorFromRGB(hexRGBValue) [UIColor colorWithRed:((float)((hexRGBValue & 0xFF0000) >> 16))/255.0 green:((float)((hexRGBValue & 0xFF00) >> 8))/255.0 blue:((float)(hexRGBValue & 0xFF))/255.0 alpha:1.0]

// This will hide the empty table grid below the cells if they do not cover the entire screen

- (UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section
{
    UIView *view = nil;

    if (IS_OS_VERSION_7 /* && <is this the last section of the data source> */)
    {
        CGFloat height = 1 / [UIScreen mainScreen].scale;
        view = [[UIView alloc] initWithFrame:CGRectMake(0., 0., 320., height)];
        view.backgroundColor = UIColorFromRGB(0xC8C7CC);
        view.autoresizingMask = UIViewAutoresizingFlexibleWidth;
    }
    else
    {
        view = [UIView new];
    }
    return view;
}


- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section
{
    if (IS_OS_VERSION_7 /* && <is this the last section of the data source> */)
    {
        return 1 / [UIScreen mainScreen].scale;
    }
    else
    {
        // This will hide the empty table grid below the cells if they do not cover the entire screen
        return 0.01f;
    }
}
ivohad
  • 211
  • 2
  • 5
2

This fixed the issue for me:

Make sure clipsToBounds is set to YES for the cell, but NO for the cell's contentView. Also set cell.contentView.backgroundColor = [UIColor clearColor];

Divya Bhaloidiya
  • 5,018
  • 2
  • 25
  • 45
JimmyB
  • 326
  • 3
  • 12
2

Seems like this issue manifests under so many circumstances.

For me it had something to do with cell selection. I have no idea why and didn't have time to dig into it too deep, but I can say it started occurring when I set the cell's selectionStyle to none. ie:

//This line brought up the issue for me
cell.selectionStyle = UITableViewCellSelectionStyleNone;

I tried using some of the delegate methods above that toggle on and off the separatorStyle property of the tableView but they didn't seem to do anything to fix my issue.

The whole reason why I needed that was because I didn't even need cell selection.

So, I did find something that worked for me. I just disabled selection on the UITableView:

tableView.allowsSelection = NO;

Hope this helps someone, if you don't need to have cell selection.

Arjun Mehta
  • 2,500
  • 1
  • 24
  • 40
2

I tried so many suggestions to fix but cannot fix that.Finally I decided to custom separator line as below:

func tableView(tableView: UITableView, willDisplayCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) {
    var lineView = UIView(frame: CGRectMake(20, cell.contentView.frame.size.height - 1.0, cell.contentView.frame.size.width - 20, 1))

    lineView.backgroundColor = UIColor(red: 170.0/255.0, green: 170.0/255.0, blue: 170.0/255.0, alpha: 1)
    cell.contentView.addSubview(lineView)
}

P/S: custom at willDisplayCell NOT cellForRowAtIndexPath

lee
  • 7,955
  • 8
  • 44
  • 60
1

Quite surprisingly, changing cell's separatorInset value back and forth seems to be working:

NSIndexPath *selectedPath = [self.controller.tableView indexPathForSelectedRow];
[self.controller.tableView deselectRowAtIndexPath:selectedPath animated:YES];

UITableViewCell *cell = [self.controller.tableView cellForRowAtIndexPath:selectedPath];
UIEdgeInsets insets = cell.separatorInset;
cell.separatorInset = UIEdgeInsetsMake(0.0, insets.left + 1.0, 0.0, 0.0);
cell.separatorInset = insets;
Bartosz Ciechanowski
  • 10,293
  • 5
  • 45
  • 60
1

To fix the above issue, add empty footer in viewDidLoad.

UIView *emptyView_ = [[UIView alloc] initWithFrame:CGRectZero];   
emptyView_.backgroundColor = [UIColor clearColor];  
[tableView setTableFooterView:emptyView_];

Please don't use the above lines in viewForFooterInSection delegate method. Means Dont implement viewForFooterInSection method.

beryllium
  • 29,669
  • 15
  • 106
  • 125
1

I also had the problem of this inconsistent separator line display at the bottom of my UITableView. Using a custom footer view, I have been able to create a similar line and to display it on top of the potential existing one (which was sometimes missing).

The only problem of this solution is that Apple may change one day the thickness of the line

- (UIView*) tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section
{
    float w = tableView.frame.size.width;

    UIView * footerView =  [[UIView alloc] initWithFrame:CGRectMake(0, 0, w, 1)];
    footerView.autoresizingMask = UIViewAutoresizingFlexibleWidth;
    footerView.clipsToBounds=NO;

    UIView* separatoraddon = [[UIView alloc] initWithFrame:CGRectMake(0, -.5, w, .5)];
    separatoraddon.autoresizingMask = UIViewAutoresizingFlexibleWidth;
    separatoraddon.backgroundColor = tableView.separatorColor;
    [footerView addSubview:separatoraddon];

    return footerView;
}
- (CGFloat) tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section
{
    return 1;
}
Paco_777
  • 216
  • 2
  • 10
1

I've resolved putting these lines of code where the update of the tableview hapens:

self.tableView.separatorStyle = UITableViewCellSeparatorStyle.None;
self.tableView.separatorStyle = UITableViewCellSeparatorStyle.SingleLine;

For example, in my case i've putted them here:

tableView.beginUpdates()
tableView.insertRowsAtIndexPaths(insertIndexPaths, withRowAnimation: UITableViewRowAnimation.Fade)
tableView.endUpdates()
self.tableView.separatorStyle = UITableViewCellSeparatorStyle.None;
self.tableView.separatorStyle = UITableViewCellSeparatorStyle.SingleLine;
msalafia
  • 2,703
  • 5
  • 23
  • 34
1

You need to remove a cell selection before you doing cell's update. Then you could restore selection.

NSIndexPath *selectedPath = [self.tableview indexPathForSelectedRow];
    [self.tableview deselectRowAtIndexPath:selectedPath animated:NO];
    [self.tableview reloadRowsAtIndexPaths:@[ path ] withRowAnimation:UITableViewRowAnimationNone];
    [self.tableview selectRowAtIndexPath:selectedPath animated:NO scrollPosition:UITableViewScrollPositionNone];
Voloda2
  • 12,359
  • 18
  • 80
  • 130
0

to expand on airpaulg answer, because it didn't entirely work for me..

i had to also implement the heightforfooter method to get the height

then i noticed the lightgraycolor is too dark. i fixed this by grabbing the current separator color of the tableview and using that:

UIColor *separatorGray = [self.briefcaseTableView separatorColor]; [footerSeparator setBackgroundColor:separatorGray];

skinsfan00atg
  • 571
  • 1
  • 3
  • 19
0

I also ran into this problem in our project. My table view had a tableFooterView which could make this happen. I found the separator below the last row would appear if I removed that tableFooterView.

xT_Tx
  • 1
0

What made the difference for me was reloading the row for which the bottom separator line would not appear:

NSIndexPath *indexPath = 
     [NSIndexPath indexPathForRow:rowIndex inSection:sectionIndex];  
[self.tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone];
Don Miguel
  • 882
  • 9
  • 19
0

I solve this problem in another way: add a layer that its height is 0.5px and its color is lightgray into tableview.tableFooterView as its sublayer.

the code is just like this:

UIView *tableFooterView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 70)];
CALayer *topSeperatorLine = [CALayer layer];
topSeperatorLine.borderWidth = 0.5f;
topSeperatorLine.borderColor = [UIColor lightGrayColor].CGColor;
topSeperatorLine.frame = CGRectMake(0, 0, 320, 0.5f);
[tableFooterView.layer addSublayer:topSeperatorLine];
self.tableView.tableFooterView = tableFooterView;
jianpx
  • 3,190
  • 1
  • 30
  • 26
0

In your UITableViewCell Subclass implement layoutSubviews and add:

- (void)layoutSubviews{
    [super layoutSubviews]
    for (UIView *subview in self.contentView.superview.subviews) {
        if ([NSStringFromClass(subview.class) hasSuffix:@"SeparatorView"]) {
            CGRect separatorFrame = subview.frame;
            separatorFrame.size.width = self.frame.size.width;
            subview.frame = separatorFrame;
        }
    }
}
Giorgos Ath
  • 1,405
  • 14
  • 16
0

As someone else mentioned, this problem seems to manifest in a variety of ways. I resolved my issue via the following workaround:

[tableView beginUpdates];
[tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone];
[tableView endUpdates];
chinabuffet
  • 5,278
  • 9
  • 40
  • 64
0

Going through the answers and solutions I came up with such observations:

This seems to be problematic in both iOS 7 and 8. I noticed the problem when selecting cell from code in viewDidLoad method so:

1) workaround was doing so in viewDidAppear: if someone doesn't mind the noticeable delay between presenting the view and selecting the cell

2) the second solution worked for me but the code looks a bit fragile as it base on the internal implementation of the UITableViewCell

3) adding own separator seems to be the most flexible and best for now but require more coding :)

Community
  • 1
  • 1
Julian
  • 9,299
  • 5
  • 48
  • 65
0

Setting the style in viewWillAppear worked for me.

Konrad Krakowiak
  • 12,285
  • 11
  • 58
  • 45
villy393
  • 2,985
  • 20
  • 28
0

As this is still an issue with IOS 8, I will add my solution in Swift. Set the tableview separator line to none. Then add this code to the cellForRowAtIndexPath delegate method. It will add a nice separator. The if statement allows to decide which cells should have a separator.

    var separator:UIView!
    if let s = cell.viewWithTag(1000)
    {
        separator = s
    }
    else
    {
        separator = UIView()
        separator.tag = 1000
        separator.setTranslatesAutoresizingMaskIntoConstraints(false)
        cell.addSubview(separator)

        // Swiper constraints
        var leadingConstraint = NSLayoutConstraint(item: separator, attribute: .Leading, relatedBy: .Equal, toItem: cell, attribute: .Leading, multiplier: 1, constant: 15)
        var heightConstraint = NSLayoutConstraint(item: separator, attribute: .Height, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute, multiplier: 1, constant: 0.5)
        var bottomConstraint = NSLayoutConstraint(item: cell, attribute: .Bottom, relatedBy: .Equal, toItem: separator, attribute: .Bottom, multiplier: 1, constant:0)
        var trailingConstraint = NSLayoutConstraint(item: cell, attribute: .Trailing, relatedBy: .Equal, toItem: separator, attribute: .Trailing, multiplier: 1, constant: 15)
        cell.addConstraints([bottomConstraint, leadingConstraint, heightConstraint, trailingConstraint])
    }

    if indexPath.row == 3
    {
        separator.backgroundColor = UIColor.clearColor()
    }
    else
    {
        separator.backgroundColor = UIColor.blackColor()
    }
Bjørn Ruthberg
  • 336
  • 1
  • 15
0

Here's my solution to this problem. After you insert your cell(s), reload the section. If reloading the entire section is too intensive for you, just reload the indexPaths above and below.

[CATransaction begin];
[CATransaction setCompletionBlock:^{
    //  Fix for issue where seperators disappear

    [self.tableView reloadSections:[NSIndexSet indexSetWithIndex:0] withRowAnimation:UITableViewRowAnimationNone];
}];

[self.tableView insertRowsAtIndexPaths:@[ indexPath ] withRowAnimation:UITableViewRowAnimationFade];

[CATransaction commit];
mattsven
  • 22,305
  • 11
  • 68
  • 104
0

ran into a similar problem, I found that another good solution, especially if your dataSource is not large is reload the tableData when you implement the -(void)scrollViewDidScroll:(UIScrollView *)scrollView method, here's an example:

-(void)scrollViewDidScroll:(UIScrollView *)scrollView {
      if (scrollView == self.tableView1) {
          [self.tableView1 reloadData];
      }

      else {
          [self.tableView2 reloadData];
      }
}

You can also just reload non-visible data based on the visible dataSource, but that requires some more hacking.

Keep in mind this delegate function falls under the UITableViewDelegate protocol!

Hope it helps!

0

What worked for me was reloading the data after beginUpdates and endUpdates:

private func animateCellHeighChangeForTableView(tableView: UITableView, withDuration duration: Double) {
     UIView.animateWithDuration(duration) { () -> Void in
        tableView.beginUpdates();
        tableView.endUpdates();
        tableView.reloadData();
     }
}
Ali M
  • 67
  • 1
  • 8
0

The disappearing separator problem happens when I insert/delete rows with an animation. What solved it for me was to invoke deselectRowAtIndexPath()

var insertion = [NSIndexPath]()
var deletion = [NSIndexPath]()
// TODO: populate the insertion array and deletion array

tableView.beginUpdates()
tableView.deleteRowsAtIndexPaths(deletion, withRowAnimation: .Fade)
tableView.insertRowsAtIndexPaths(insertion, withRowAnimation: .Fade)
if let indexPath = tableView.indexPathForSelectedRow {
    tableView.deselectRowAtIndexPath(indexPath, animated: true)
}
tableView.endUpdates()
neoneye
  • 50,398
  • 25
  • 166
  • 151
0

A simple, clean, and efficient way to do this without having to loop through every subview of a cell, which is called every time a cell is dequeued/created, is by using good ole KVC:

UIView *separatorView = [self valueForKey:@"separatorView"]; // pull separator using KVC

if (separatorView) {
    separatorView.hidden = NO;
}

Stick that in layoutSubviews of your cell class and that should solve your problem.

Stephen Paul
  • 2,762
  • 2
  • 21
  • 25
0

Modified @Lee's Answer to get the default table view separator style and not to show separator for the last row which is odd. Hope it helps somebody.

func tableView(tableView: UITableView, willDisplayCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) {

        if indexPath.row >= yourDataSource.count - 1{
                return
        }

        let lineView = UIView(frame: CGRectMake(20, cell.contentView.frame.size.height - 1.0, cell.contentView.frame.size.width, 0.5))
        lineView.backgroundColor = tableView.separatorColor
        cell.contentView.addSubview(lineView)
    }
Satheesh
  • 10,998
  • 6
  • 50
  • 93
0

In my case, I tried all the listed answers but was not working for me, I used two answers, which worked for me. below is the solution:

add the below lines in your UITableViewConstroller

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {

       // fix for separators bug in iOS 7
    self.tableView.separatorStyle = .none;
    self.tableView.separatorStyle = .singleLine;
}

Now, override the below method in UITableViewCell

    override func layoutSubviews() {
    super.layoutSubviews()

    guard let superview = contentView.superview else {
        return
    }
    for subview in superview.subviews {
        if String(describing: type(of: subview)).hasSuffix("SeparatorView") {
            subview.isHidden = false
        }
    }
}

I hope this will work for others as well. Thanks

Naveed Ahmad
  • 6,627
  • 2
  • 58
  • 83
-1

One and only fix: Write the below lines of code above @implementation of .m file from which the tableView exists.

@interface UITableViewCell (fixSeparator)
- (void)layoutSubviews;

@end

@implementation UITableViewCell (fixSeparator)

- (void)layoutSubviews {
    [super layoutSubviews];

    for (UIView *subview in self.contentView.superview.subviews) {
        if ([NSStringFromClass(subview.class) hasSuffix:@"SeparatorView"]) {
            subview.hidden = NO;
        }
    }
}

@end
YSR fan
  • 705
  • 6
  • 11
-3

I solved this problem by setting in IB: Separator Inset = custom, left = 0, right = 0

Yuri
  • 1