I tried to implement built-in CollectionView reordering that was presented starting from iOS10 according to this guide: http://nshint.io/blog/2015/07/16/uicollectionviews-now-have-easy-reordering/
and everything work fine on iOS11, but have crash on iOS10 when starting drag any item (cell) in UICollectionView
Here is my code:
- (void)addCollectionViewGestureRecognizers
{
if (!self.panGesture)
{
// gesture to drag and reorder tiles
self.panGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(handleCollectionViewPanGesture:)];
[self.collectionView addGestureRecognizer:self.panGesture];
}
}
- (BOOL)collectionView:(UICollectionView *)collectionView canMoveItemAtIndexPath:(NSIndexPath *)indexPath
{
return YES;
}
- (void)collectionView:(UICollectionView *)collectionView moveItemAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath
{
CLog(#"Item moved from index path: %# to index path: %#", sourceIndexPath, destinationIndexPath);
}
- (void)handleCollectionViewPanGesture:(UIPanGestureRecognizer *)gesture
{
switch(gesture.state)
{
case UIGestureRecognizerStateBegan:
{
NSIndexPath *selectedIndexPath = [self.collectionView indexPathForItemAtPoint:[gesture locationInView:self.collectionView]];
if(selectedIndexPath)
{
[self.collectionView beginInteractiveMovementForItemAtIndexPath:selectedIndexPath];
}
break;
}
case UIGestureRecognizerStateChanged:
{
[self.collectionView updateInteractiveMovementTargetPosition:[gesture locationInView:gesture.view]];
break;
}
case UIGestureRecognizerStateEnded:
{
[self.collectionView endInteractiveMovement];
break;
}
default:
{
[self.collectionView cancelInteractiveMovement];
break;
}
}
}
and iOS 10 every time crashes on line:
[self.collectionView updateInteractiveMovementTargetPosition:[gesture locationInView:guesture.view]];
Crash report:
0 CoreFoundation 0x0000000118f8bb0b __exceptionPreprocess + 171
1 libobjc.A.dylib 0x0000000118961141 objc_exception_throw + 48
2 CoreFoundation 0x0000000118ec0443 -[__NSArrayM insertObject:atIndex:] + 1603
3 UIKit 0x00000001166f3577 -[UICollectionView _getOriginalReorderingIndexPaths:targetIndexPaths:] + 501
4 UIKit 0x00000001166e2e50 -[UICollectionView _viewAnimationsForCurrentUpdate] + 7338
5 UIKit 0x00000001166e7bf3 __71-[UICollectionView _updateWithItems:tentativelyForReordering:animator:]_block_invoke.2012 + 197
6 UIKit 0x0000000115e4c08e +[UIView(Animation) performWithoutAnimation:] + 90
7 UIKit 0x00000001166e682d -[UICollectionView _updateWithItems:tentativelyForReordering:animator:] + 3856
8 UIKit 0x00000001166e0b33 -[UICollectionView _endItemAnimationsWithInvalidationContext:tentativelyForReordering:animator:] + 17030
9 UIKit 0x00000001166e91cd -[UICollectionView _endUpdatesWithInvalidationContext:tentativelyForReordering:animator:] + 71
10 UIKit 0x00000001166e9514 -[UICollectionView _performBatchUpdates:completion:invalidationContext:tentativelyForReordering:animator:] + 437
11 UIKit 0x00000001166e933c -[UICollectionView _performBatchUpdates:completion:invalidationContext:tentativelyForReordering:] + 91
12 UIKit 0x00000001166f09a3 -[UICollectionView _updateReorderingTargetPosition:forced:] + 1467
13 UIKit 0x00000001166f122a -[UICollectionView updateInteractiveMovementTargetPosition:] + 29
14 myAPP 0x000000010dcb3b26 -[MenuCollectionViewController handleCollectionViewPanGesture:] + 710
15 UIKit 0x00000001162c8f59 -[UIGestureRecognizerTarget _sendActionWithGestureRecognizer:] + 57
16 UIKit 0x00000001162d0d57 _UIGestureRecognizerSendTargetActions + 109
17 UIKit 0x00000001162ce70b _UIGestureRecognizerSendActions + 225
Am I forgot to set something?
I will very appreciate if someone have any ideas regarding this...
Ok, seems I found a reason of that crash and possible solution.
I have custom layout inherited from UICollectionViewFlowLayout and override function targetIndexPathForInteractivelyMovingItem in it. To move items to correct place.
I implemented it like this:
- (NSIndexPath*)targetIndexPathForInteractivelyMovingItem:(NSIndexPath *)previousIndexPath withPosition:(CGPoint)position
{
NSIndexPath *targetIndexPath = [self.collectionView indexPathForItemAtPoint:position];
return targetIndexPath;
}
And this works fine on iOS 11, but for iOS 10 indexPathForItemAtPoint returns nil for some reason (I don't sure why)
So I had to add this trick to prevent crash on reordering
- (NSIndexPath*)targetIndexPathForInteractivelyMovingItem:(NSIndexPath *)previousIndexPath withPosition:(CGPoint)position
{
NSIndexPath *targetIndexPath = [self.collectionView indexPathForItemAtPoint:position];
if (!targetIndexPath) // on iOS10 indexpath can be nil by some reason
{
targetIndexPath = [NSIndexPath indexPathForRow:0 inSection:0];
}
return targetIndexPath;
}
Related
sometimes setting collectionViewLayout when app launch, causes this fatal exception:
Do you have an idea why?
There is no update since it's during app launch.
And I am not able to reproduce it.
I got a lot of crashes from Crashlytics.
Fatal Exception: NSInternalInconsistencyException Cannot set the layout [<StreamContainerLayoutIPad: 0x1056a4e60>] for [<DMZFixedCollectionView: 0x10593f600; baseClass = UICollectionView; frame = (0 0; 375 667); clipsToBounds = YES; opaque = NO; autoresize = RM+BM; gestureRecognizers = <NSArray: 0x283906640>; layer = <CALayer: 0x2837dd1a0>; contentOffset: {0, 0}; contentSize: {0, 0}; adjustedContentInset: {0, 0, 0, 0}> collection view layout: <UICollectionViewLayout: 0x10566f620>] during an update.
Stacktrace:
Fatal Exception: NSInternalInconsistencyException
0 CoreFoundation 0x183df7ea0 __exceptionPreprocess
1 libobjc.A.dylib 0x182fc9a40 objc_exception_throw
2 CoreFoundation 0x183d0dc1c +[_CFXNotificationTokenRegistration keyCallbacks]
3 Foundation 0x1847fb140 -[NSAssertionHandler handleFailureInMethod:object:file:lineNumber:description:]
4 UIKitCore 0x1b089ac4c -[UICollectionView _setCollectionViewLayout:animated:isInteractive:completion:animator:]
5 UIKitCore 0x1b089aaa8 -[UICollectionView _setCollectionViewLayout:animated:isInteractive:completion:]
6 UIKitCore 0x1b089a668 -[UICollectionView setCollectionViewLayout:]
7 Vero 0x1048f52e4 -[StreamCompressionController setup] (__hidden#27104_:77)
8 Vero 0x10491d0ac -[StreamMainViewController viewWillAppear:] (__hidden#26011_:227)
9 UIKitCore 0x1b0a038ec -[UIViewController _setViewAppearState:isAnimating:]
10 UIKitCore 0x1b0a03fd0 -[UIViewController __viewWillAppear:]
Here is my code in setup method:
- (void)setup
{
CollectionLayout *newLayout = [self createLayout];
_collectionView.collectionViewLayout = newLayout;
_layout = newLayout;
}
PS: What is strange is that is occurred only on iPhone and not on iPad.
The application is crashing below I don't know it seems like apple bug.. if any one faced the same problem please update me
[self.collectionView performBatchUpdates: —>// crashing here
^{
if (indexToInsertAt == count)
{
// Add cell at end of list
[self.restaurantList addObject:cellData];
NSIndexPath *indexPath = [NSIndexPath indexPathForItem:indexToInsertAt
inSection:0];
[self.collectionView insertItemsAtIndexPaths:#[indexPath]];
}
else
{
// Insert cell
[self.restaurantList insertObject:cellData
atIndex:indexToInsertAt];
NSIndexPath *indexPath = [NSIndexPath indexPathForItem:indexToInsertAt
inSection:0];
[self.collectionView insertItemsAtIndexPaths:#[indexPath]];
}
}
completion:^(BOOL finished)
{
// Do nothing
}];
crash log are here:
Crashed: com.apple.main-thread
SIGABRT ABORT at 0x3baff1f0
raw
0
libsystem_kernel.dylib
__pthread_kill + 8
10
Foundation
-[NSAssertionHandler handleFailureInMethod:object:file:lineNumber:description:] + 90
11
UIKit
__45-[UICollectionViewData validateLayoutInRect:]_block_invoke + 1206
12
UIKit
-[UICollectionViewData validateLayoutInRect:] + 938
13
UIKit
-[UICollectionView layoutSubviews] + 156
14
UIKit
-[UIView(CALayerDelegate) layoutSublayersOfLayer:] + 380
15
QuartzCore
-[CALayer layoutSublayers] + 142
16
QuartzCore
CA::Layer::layout_if_needed(CA::Transaction*) + 350
17
UIKit
-[UIView(Hierarchy) layoutBelowIfNeeded] + 550
18
UIKit
-[UICollectionView performBatchUpdates:completion:] + 170
crash is happening rearly please help me out
thanks in advance....
My intent is to have 2 separate view controllers for a NSSplitView with two panes. In the left pane I want a table view, but it crashes. Here's the scenario:
I have a simple project with a MainMenu.xib, AppDelegate.h/m. In this project I add a LeftPaneViewController.h/.m/.xib.
In MainMenu.xib I add a NSSplitView to the default view.
In AppDelegate.h:
#property (weak) IBOutlet NSSplitView *splitView;
In AppDelegate.m:
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
// Insert code here to initialize your application
LeftPaneViewController *lpvc = [[LeftPaneViewController alloc] initWithNibName:#"LeftPaneViewController" bundle:nil];
[self.splitView replaceSubview:[[self.splitView subviews] objectAtIndex:0] with:lpvc.view];
}
I connect the NSSplitView in MainMenu.xib to splitView in the AppDelegate.
When I run this works fine, but of course there is nothing to see yet.
In LeftPaneViewController.xib I add a NSTableView to the default custom view. I delete one of the columns (the bottom one in the list).
In LeftPaneViewController.h:
#interface LeftPaneViewController : NSViewController <NSTableViewDelegate, NSTableViewDataSource>
#property (weak) IBOutlet NSTableView *tableView;
#property (nonatomic, retain) NSMutableArray *tableDataSource;
In LeftPaneViewController.m:
#import "LeftPaneViewController.h"
#interface LeftPaneViewController ()
#end
#implementation LeftPaneViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Initialization code here.
}
return self;
}
- (void)awakeFromNib
{
self.tableDataSource = [[NSMutableArray alloc] initWithObjects:#"Row1", #"Row2", nil];
[self.tableView setNeedsDisplay];
}
- (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView
{
// This is a defensive move
// There are cases where the nib containing the NSTableView can be loaded before the data is populated
// by ensuring the count value is 0 and checking to see if the namesArray is not nil, the app
// is protecting itself agains that situation
NSInteger count=0;
if (self.tableDataSource)
count=[self.tableDataSource count];
return count;
}
- (NSView *)tableView:(NSTableView *)tableView viewForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row {
// Get an existing cell with the MyView identifier if it exists
NSTextField *result = [tableView makeViewWithIdentifier:#"LeftPaneCell" owner:self];
// There is no existing cell to reuse so create a new one
if (result == nil) {
// Create the new NSTextField with a frame of the {0,0} with the width of the table.
// Note that the height of the frame is not really relevant, because the row height will modify the height.
NSTextField *textField;
textField = [[NSTextField alloc] initWithFrame:NSMakeRect(2, 456, 125, 20)];
[textField setStringValue:#"My Label"];
[textField setBezeled:NO];
[textField setDrawsBackground:NO];
[textField setEditable:NO];
[textField setSelectable:NO];
[self.view addSubview:textField];
// The identifier of the NSTextField instance is set to MyView.
// This allows the cell to be reused.
result.identifier = #"LeftPaneCell";
}
// result is now guaranteed to be valid, either as a reused cell
// or as a new cell, so set the stringValue of the cell to the
// nameArray value at row
result.stringValue = [self.tableDataSource objectAtIndex:row];
// Return the result
return result;
}
#end
In the LeftPaneViewController.xib I hook the TableView dataSource and delegate to "File's Owner" (of LeftPaneViewController of course). and hook the tableView referencing outlet to the tableView in LeftPaneViewController.h. I checked these at least a thousand times ;-)
Then when I run I get the following crash log:
* thread #1: tid = 0x23427, 0x00007fff82893250 libobjc.A.dylib`objc_msgSend + 16, queue = 'com.apple.main-thread, stop reason = EXC_BAD_ACCESS (code=EXC_I386_GPFLT)
frame #0: 0x00007fff82893250 libobjc.A.dylib`objc_msgSend + 16
frame #1: 0x00007fff88f8d972 AppKit`-[NSTableRowData _addViewToRowView:atColumn:row:] + 324
frame #2: 0x00007fff88f8d63f AppKit`-[NSTableRowData _addViewsToRowView:atRow:] + 151
frame #3: 0x00007fff88f8bbd5 AppKit`-[NSTableRowData _addRowViewForVisibleRow:withPriorView:] + 415
frame #4: 0x00007fff88f8b95a AppKit`-[NSTableRowData _addRowViewForVisibleRow:withPriorRowIndex:inDictionary:withRowAnimation:] + 272
frame #5: 0x00007fff88f8ac29 AppKit`-[NSTableRowData _unsafeUpdateVisibleRowEntries] + 740
frame #6: 0x00007fff88f8a7c1 AppKit`-[NSTableRowData updateVisibleRowViews] + 119
frame #7: 0x00007fff88f625a7 AppKit`-[NSTableView layout] + 165
frame #8: 0x00007fff88f15e65 AppKit`-[NSView _layoutSubtreeHeedingRecursionGuard:] + 112
frame #9: 0x00007fff8d11b4a6 CoreFoundation`__NSArrayEnumerate + 582
frame #10: 0x00007fff88f15fc6 AppKit`-[NSView _layoutSubtreeHeedingRecursionGuard:] + 465
frame #11: 0x00007fff8d11b4a6 CoreFoundation`__NSArrayEnumerate + 582
frame #12: 0x00007fff88f15fc6 AppKit`-[NSView _layoutSubtreeHeedingRecursionGuard:] + 465
frame #13: 0x00007fff8d11b4a6 CoreFoundation`__NSArrayEnumerate + 582
frame #14: 0x00007fff88f15fc6 AppKit`-[NSView _layoutSubtreeHeedingRecursionGuard:] + 465
frame #15: 0x00007fff8d11b4a6 CoreFoundation`__NSArrayEnumerate + 582
frame #16: 0x00007fff88f15fc6 AppKit`-[NSView _layoutSubtreeHeedingRecursionGuard:] + 465
frame #17: 0x00007fff8d11b4a6 CoreFoundation`__NSArrayEnumerate + 582
frame #18: 0x00007fff88f15fc6 AppKit`-[NSView _layoutSubtreeHeedingRecursionGuard:] + 465
frame #19: 0x00007fff8d11b4a6 CoreFoundation`__NSArrayEnumerate + 582
frame #20: 0x00007fff88f15fc6 AppKit`-[NSView _layoutSubtreeHeedingRecursionGuard:] + 465
frame #21: 0x00007fff88f15cfe AppKit`-[NSView layoutSubtreeIfNeeded] + 615
frame #22: 0x00007fff88f114ac AppKit`-[NSWindow(NSConstraintBasedLayout) layoutIfNeeded] + 201
frame #23: 0x00007fff88e0b0a8 AppKit`_handleWindowNeedsDisplayOrLayoutOrUpdateConstraints + 446
frame #24: 0x00007fff893d6901 AppKit`__83-[NSWindow _postWindowNeedsDisplayOrLayoutOrUpdateConstraintsUnlessPostingDisabled]_block_invoke_01208 + 46
frame #25: 0x00007fff8d0e9417 CoreFoundation`__CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 23
frame #26: 0x00007fff8d0e9381 CoreFoundation`__CFRunLoopDoObservers + 369
frame #27: 0x00007fff8d0c47b8 CoreFoundation`__CFRunLoopRun + 728
frame #28: 0x00007fff8d0c40e2 CoreFoundation`CFRunLoopRunSpecific + 290
frame #29: 0x00007fff8c17aeb4 HIToolbox`RunCurrentEventLoopInMode + 209
frame #30: 0x00007fff8c17ab94 HIToolbox`ReceiveNextEventCommon + 166
frame #31: 0x00007fff8c17aae3 HIToolbox`BlockUntilNextEventMatchingListInMode + 62
frame #32: 0x00007fff88e08533 AppKit`_DPSNextEvent + 685
frame #33: 0x00007fff88e07df2 AppKit`-[NSApplication nextEventMatchingMask:untilDate:inMode:dequeue:] + 128
frame #34: 0x00007fff88dff1a3 AppKit`-[NSApplication run] + 517
frame #35: 0x00007fff88da3bd6 AppKit`NSApplicationMain + 869
frame #36: 0x0000000100001872 TableView_In_SplitView`main(argc=3, argv=0x00007fff5fbff7e8) + 34 at main.m:13
frame #37: 0x00007fff84d4d7e1 libdyld.dylib`start + 1
With breakpoints I determine that in LeftPaneViewController.m the numberOfRowsInTableView is called and returns 2, but viewForTableColumn is not called.
The TableView is Cell Based so I do expect the viewForTableColumn to be called.
If I simply add a NSTableView to the SplitView in MainMenu.xib and transfer the same code into AppDelegate.h/.m it works fine (and changing the hooks as well of course). That is, it does not crash and both numberOfRowsInTableView and viewForTableColumn are called.
So what am I not doing that is causing the crash?
Ok, found the answer. Since the LeftPaneViewController variable (lpvc) in AppDelegate.m was local it was being released after the replaceSubview call. So adding it as (nonatomic, retain) in AppDelegate.h fixed the crash. Turned on Zombies to find the answer ;-).
I'm working on an application where I have a custom subclass of UITableViewCell. I want to make the cell's height dynamic based on the text inside it. I try do do that in my heightForRowAtIndexPath method. But I'm having some issues, the following code causes and EXC_BAD_ACCESS(code=2 address=0xb7ffffcc) error.
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
PostCell *cell = (PostCell *)[tableView cellForRowAtIndexPath:indexPath];
CGSize postTextSize;
if (![cell.postText.text isEqualToString:#""]) {
postTextSize = [cell.postText.text sizeWithFont:[UIFont systemFontOfSize:14] constrainedToSize:CGSizeMake(cell.postText.frame.size.width, 200)];
} else {
postTextSize = CGSizeMake(cell.postText.frame.size.width, 40);
}
return postTextSize.height + cell.userName.frame.size.height + 10;
}
If I instead have:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return 100;
}
It works.
It seems to be crashing on this line: PostCell *cell = (PostCell *)[tableView cellForRowAtIndexPath:indexPath];, and I don't know why. I have tried to build clean and reset the simulator, but neither worked. Any ideas why this is happening?
I have tried to reproduce the problem. It turns out that calling cellForRowAtIndexPath: inside heightForRowAtIndexPath causes heightForRowAtIndexPath to be called recursively. Here is an extract of the stack backtrace after the 3 recursion steps:
frame #0: 0x000042d0 DocInteraction`-[DITableViewController tableView:heightForRowAtIndexPath:] + 48 at DITableViewController.m:262
frame #1: 0x0054f688 UIKit`-[UISectionRowData refreshWithSection:tableView:tableViewRowData:] + 3437
frame #2: 0x0055040f UIKit`-[UITableViewRowData(UITableViewRowDataPrivate) _ensureSectionOffsetIsValidForSection:] + 144
frame #3: 0x00551889 UIKit`-[UITableViewRowData numberOfRows] + 137
frame #4: 0x00553dac UIKit`-[UITableViewRowData globalRowsInRect:] + 42
frame #5: 0x003f82eb UIKit`-[UITableView(_UITableViewPrivate) _visibleGlobalRowsInRect:] + 177
frame #6: 0x004001e6 UIKit`-[UITableView cellForRowAtIndexPath:] + 113
frame #7: 0x000042f2 DocInteraction`-[DITableViewController tableView:heightForRowAtIndexPath:] + 82 at DITableViewController.m:262
frame #8: 0x0054f688 UIKit`-[UISectionRowData refreshWithSection:tableView:tableViewRowData:] + 3437
frame #9: 0x0055040f UIKit`-[UITableViewRowData(UITableViewRowDataPrivate) _ensureSectionOffsetIsValidForSection:] + 144
frame #10: 0x00551889 UIKit`-[UITableViewRowData numberOfRows] + 137
frame #11: 0x00553dac UIKit`-[UITableViewRowData globalRowsInRect:] + 42
frame #12: 0x003f82eb UIKit`-[UITableView(_UITableViewPrivate) _visibleGlobalRowsInRect:] + 177
frame #13: 0x004001e6 UIKit`-[UITableView cellForRowAtIndexPath:] + 113
frame #14: 0x000042f2 DocInteraction`-[DITableViewController tableView:heightForRowAtIndexPath:] + 82 at DITableViewController.m:262
frame #15: 0x0054f688 UIKit`-[UISectionRowData refreshWithSection:tableView:tableViewRowData:] + 3437
frame #16: 0x0055040f UIKit`-[UITableViewRowData(UITableViewRowDataPrivate) _ensureSectionOffsetIsValidForSection:] + 144
frame #17: 0x00551889 UIKit`-[UITableViewRowData numberOfRows] + 137
frame #18: 0x003ff66d UIKit`-[UITableView noteNumberOfRowsChanged] + 119
frame #19: 0x003ff167 UIKit`-[UITableView reloadData] + 764
Finally the program crashes. On my Simulator this happens when the back trace is about 57000 levels deep.
Old answer (not wrong, but does not explain the
EXC_BAD_ACCESS):
The problem is that
[tableView cellForRowAtIndexPath:indexPath]
returns nil for rows that are currently not visible. A table view allocates only so many cells that are required to display the currently visible rows. The cells are reused when you scroll the table view.
But heightForRowAtIndexPath is called for all cells of the table view before any row is displayed.
As a consequence, you should not get the text from the table view cells to compute the height in heightForRowAtIndexPath. You should get the text from your data source instead.
tableView heightForRowAtIndexPath is called before cellForRowAtIndexPath, before a cell is displayed, the height needs to be calculated first.
you should get text from your data source, not from cell
I had a similar problem and came across, just to share what I do now which works well for me
CGFloat mycell_height;
- (void)viewDidLoad
{
[super viewDidLoad];
UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:#"MyCell"];
mycell_height = cell.frame.size.height;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return mycell_height; //assuming all cells are the same
}
Hope this helps anyone looking for this and new to iOS programming like me :-)
In this case you should call UITableViewDataSource method for getting cell for indexPath instead of cellForRowAtIndexPath: method of UITableView because at the moment when tableView: heightForRowAtIndexPath: first time called there are no any cells in tableView.
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath: (NSIndexPath *)indexPath {
PostCell *cell = (PostCell *)[self tableView:tableView cellForRowAtIndexPath:indexPath];
CGSize postTextSize;
if (![cell.postText.text isEqualToString:#""]) {
postTextSize = [cell.postText.text sizeWithFont:[UIFont systemFontOfSize:14] constrainedToSize:CGSizeMake(cell.postText.frame.size.width, 200)];
} else {
postTextSize = CGSizeMake(cell.postText.frame.size.width, 40);
}
return postTextSize.height + cell.userName.frame.size.height + 10;
}
It works and no causes EXC_BAD_ACCESS exception.
SWIFT:
Use this to know when the tables have loaded:
extension UITableView {
func reloadData(completion: ()->()) {
UIView.animateWithDuration(0, animations: { self.reloadData() })
{ _ in completion() }
}
}
Create a boolean value
var tables_loaded = Bool(false)
Then in viewDidLoad:
tableView.reloadData {
tables_loaded = true
// call functions or other stuff regarding table manipulation.
// tableView.beginUpdates()
// tableView.endUpdates()
}
then in
override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
if tables_loaded {
let cell = tableView.cellForRowAtIndexPath(indexPath)
// Do your magic here!
}
}
I am making a iPhone app with a login feature. After they login, I have it write to a database. When the user opens the app, I want it to check whether or not to go to the app or show a UIView for them to login. I have some code, but it crashes. Here it is:
- (void)applicationDidFinishLaunching:(UIApplication *)application {
sleep(5);
// Configure and show the window
[window addSubview:[navigationController view]];
[window makeKeyAndVisible];
//[application setStatusBarStyle:UIStatusBarStyleBlackOpaque];
int checkLoginCount = 0;
NSArray *checkLoginInfo = [database executeQuery:#"SELECT * FROM login WHERE id != '' or email != '' or password != ''"];
for (NSDictionary *checkLoginRow in checkLoginInfo) {
checkLoginCount++;
}
NSLog(#"alsdfjaldfksjalsdfjkas %d", checkLoginCount);
if (checkLoginCount == 0) {
SplashPageViewController *screentwo = [[SplashPageViewController alloc] initWithNibName:#"splashPage" bundle:nil];
//NSLog(#"aldjksflasdfjadksaldfjsaldksfj %#", screentwo);
screentwo.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
[self presentModalViewController:screentwo animated:NO];
[screentwo release];
} else {
splashView = [[UIImageView alloc] initWithFrame:CGRectMake(0,0, 320, 480)];
splashView.image = [UIImage imageNamed:#"Default.png"];
[window addSubview:splashView];
[window bringSubviewToFront:splashView];
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0.5];
[UIView setAnimationTransition:UIViewAnimationTransitionNone forView:window cache:YES];
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:#selector(startupAnimationDone:finished:context:)];
splashView.alpha = 0.0;
//splashView.frame = CGRectMake(-60, -60, 440, 600);
[UIView commitAnimations];
}
}
And here's the error:
-[TableViewAppDelegate presentModalViewController:animated:]: unrecognized selector sent to instance 0x4e3e860
TableView[15309:207] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[TableViewAppDelegate presentModalViewController:animated:]: unrecognized selector sent to instance 0x4e3e860'
*** Call stack at first throw:
(
0 CoreFoundation 0x00fccbe9 __exceptionPreprocess + 185
1 libobjc.A.dylib 0x011215c2 objc_exception_throw + 47
2 CoreFoundation 0x00fce6fb -[NSObject(NSObject) doesNotRecognizeSelector:] + 187
3 CoreFoundation 0x00f3e366 ___forwarding___ + 966
4 CoreFoundation 0x00f3df22 _CF_forwarding_prep_0 + 50
5 TableView 0x00002b02 -[TableViewAppDelegate applicationDidFinishLaunching:] + 473
6 UIKit 0x002e6253 -[UIApplication _callInitializationDelegatesForURL:payload:suspended:] + 1252
7 UIKit 0x002e855e -[UIApplication _runWithURL:payload:launchOrientation:statusBarStyle:statusBarHidden:] + 439
8 UIKit 0x002f2db2 -[UIApplication handleEvent:withNewEvent:] + 1533
9 UIKit 0x002eb202 -[UIApplication sendEvent:] + 71
10 UIKit 0x002f0732 _UIApplicationHandleEvent + 7576
11 GraphicsServices 0x0186fa36 PurpleEventCallback + 1550
12 CoreFoundation 0x00fae064 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__ + 52
13 CoreFoundation 0x00f0e6f7 __CFRunLoopDoSource1 + 215
14 CoreFoundation 0x00f0b983 __CFRunLoopRun + 979
15 CoreFoundation 0x00f0b240 CFRunLoopRunSpecific + 208
16 CoreFoundation 0x00f0b161 CFRunLoopRunInMode + 97
17 UIKit 0x002e7fa8 -[UIApplication _run] + 636
18 UIKit 0x002f442e UIApplicationMain + 1160
19 TableView 0x000027f6 main + 84
20 TableView 0x00002799 start + 53
21 ??? 0x00000001 0x0 + 1
)
terminate called after throwing an instance of 'NSException'
database isn't nil
Maybe I can't do that action in that method. Who knows. Any help is appreciated! Coulton!
First of all sleep(5); is a bad idea, you should avoid using sleep on the main thread (and better don't use it anywhere).
Seems that you have all your code in one file (main app delegate) and it also is a tableview delegate? Thats why you have so messy code, try to divide logic in two groups.
For example, you can show your modal views with the help of navigation controller:
[[self navigationController] presentModalViewController:modalViewController animated:YES];
and dismiss it using
[self.navigationController dismissModalViewControllerAnimated:YES];
In iOS, you can display views modally by presenting the controller for the modal view from your current view controller. So you have get any view controller loaded before.