UITableView reloadData doesn't work? - uitableview

I tried to write a test demo for an IM app,so I designed a simple UI to chat with other buddy:while I send a message out I will reload the UITableView to show the message as the same as i receive a message.
The problem is,when I send out the message,the UITableView will refresh after I call the reloadData method,but when I receive a message it doesn't work at all,I have to pull down or up the UITableView then it will refresh.
I did set the dataSource and UITableView delegate,and I did connect the IBOutlet property with the nib file,I did check the IBOutlet property's value before I call the reloadData(it contained a valid value),and I did check the dataSource's value(when I received a message it's value changed and one message was inserted into it).
So please tell me what wrong with it after all?

Thank you #Tim very much.I caught the reason as you explained and I found that the receive message method is called by a child thread and.So change the my source code as :
dispatch_async(dispatch_get_main_queue(), ^{
[self.tv_chat_records reloadData];
});
it works!

Related

Update PickerView with new data if the view is already being shown

I am fetch data from the server to display in a picker view. If the API has not returned i display Loading... in the picker view.
Here is my use case:
API Call made to the server
User clicks button to show picker view.
Picker View is shown and displays the text LOADING...
API call returns. i call [self.seasonEpiPickerView reloadAllComponents];
Nothing happens. Basically since the picker view is already loaded and being shown on the screen it is not updating its data. How can i update the data of a picker view that is already being displayed?
You need
In .h file
#interface ViewController : UIViewController
<UIPickerViewDataSource,UIPickerViewDelegate>
In .m file set delegate and datasource
yourpicker.delegate = self;
yourpicker.datasource = self;
may this help you
Solved it: My response from the server was not on the main thread. I had put a test thread to delay UI updates for testing. I removed the test code and executed the updateUI lines from the main thread and everything works with the same above code.

[Not A Type release]: message sent to deallocated instance in UITableView

I get a crash when quickly scrolling through a UITableView.
The crash is :
*** -[Not A Type release]: message sent to deallocated instance 0x1aded1c0
And the exception breakpoint indicates this as the source:
- (void)updateInfo:(Item*)item{
if (!item) {
return;
}
Program *prg = (Program *)item;
self.titleLabel.text = prg.title; // crash here
self.descriptionLabel.text = prg.item_description;
}
This method is inside the custom table view cell subclass and it is called when data from the internet is ready to be displayed in the cell.
I have never seen this kind of crash before...
What is the best way to fix it?
Reason:
As you scroll the tableview, the cells on top get released and when data comes from internet for those cell, they have already been released. So, change your logic. You generally receive this error when you try to access and update an object which has already been released. As you are saying that this method is inside your custom cell, so it clearly indicates that the cell is already released. That's why your app gets crashed when you try to update any view of that cell.
Solution:
Either you can reload your whole tableview or reload those specific cells when you receive data.
Where are you calling the method "updateInfo"? You should call this in cellForRowAtIndexPath. You should not store a reference to a cell and then call this.
When you get the data from your service you just call self.tableView reloadData (or perhaps reloadRowsAtIndexPaths if you know which row needs update and dont want a performance hit)

Message was sent to a deallocated object (ARC)

In my app I've a UITableView in which I have custom UITableViewCells and those cells contain UIWebView in which I am displaying YouTube video using <iframe>. When I click on a video and instantly scroll the table before a full screen player opens, the app crashes. I tried Instruments to find the problem and came to know that An Objective-C message was sent to a deallocated 'AAHomeNewsListCell' object (zombie) at address: 0x118e09800.

I'm using ARC and I can't find a way to resolve this issue.
You are sending a message to an object that is no longer alive. The best way to debug that problem would probably be to set a break point as close as you can to where the situation happens, and step through the code. A good place to start would be close to where you use an AAHomeNewsListCell-object, or close to where you trigger the full screen player.
If I had to guess, I'd say that the web view is messaging its delegate but the delegate has already been deallocated. UIWebViewDelegate comes with this handy warning:
Important: Before releasing an instance of UIWebView for which you have set a delegate, you must first set the UIWebView delegate property to nil before disposing of the UIWebView instance. This can be done, for example, in the dealloc method where you dispose of the UIWebView.
Looking at your zombie message, what is it that would be still trying to message the cell? Is your cell acting as the web view's delegate?
Edit Looking at what message is being sent, it gets _setFirstResponder:. It could be a text entry form in the web view that's trying to get first responder to enter text.

How to notify UITableView on data download complete from AppDelegate when NSNotification is not an option

I have a method in AppDelegate which get some data from server, this method get called every time when application become active. I want to reload some table in another view when server data received successfully. How can i do this without using NSNotification?. I know passing notification can do this job. I want to know is there any other way to perform this?
well comments by users already explained what to do.
But i had another approach.I don't prefer, but it will work.
Always set some constant tag value to your table view (say 1001).And make sure than you never use the same tag on others.
Then in that method of appDelegate, you can do->
UITableView *tableView =(UITableView*)[self.window viewWithTag:1001];
[tableView reloadData];
I am reminding you again, don't use this. use NSNotification class.
Although it creates an unneeded dependency between the view and the app delegate, I'd implement this way:
create a ViewReloader protocol with a method - (void) reloadTable;
implement that protocol in the view
add a property of type id<ViewReloader> to the app delegate
when the view is instantiated, assign it to the property defined above
when you need to reload, call the reloadTable method of the id<ViewReloader> property from the app delegate (but always check for property != nil)
if the view is destroyed/deallocated, remember to reset the app delegate property
Well samething you can do with using custom delegates as well. If you want to pass message from one object to another. You can use notification also, but use only when you want to broadcast the message.

UITableView's reloadData sometimes does not call numberOfRowsInSection

[tableView reloadData] does not call numberOfRowsInSection:(NSInteger)section
What i would write as an answer in stackoverflow if i saw a question like this:
Be sure that delegate and dataSource is connected perfectly.
Just in case check it if you are calling it from the main thread or not.
I tried my answers before asking the question.
I put the following line in my MyTableView class (extended from UITableView)
- (void)reloadData{
NSLog(#"MyTableView (reloadData) self.dataSource: %#, delegate: %#, isMainThread: %d",self.dataSource,self.delegate,[NSThread isMainThread]);
[super reloadData];
[self.delegate performSelector:#selector(tableReloaded:) withObject:self];
}
I see that it is called from mainthread and datasource and delegate is never nil.
I am not curious about why tableView does not call cellForRow as it first has to call numberOfRows to see if the result > 0. However, it doesn't call numberOfRows too...
Any ideas? What can be the reason for tableView to giveUp calling numberOfRows function?
Update:
I've put new lines to reloadData function to print FullStack to see if it is being called from tableView's own functions. The result: They are called outside of the tableView so it there shouldn't be any unexpected behaviour.
Update2:
"Sometimes": I have discovered this problem after my users started to say that "sometimes" they don't see the changes in the table. After that, i tried to hit run button in XCode continuouslly until the app opens with this bug. (30% percentage of my runs shows this bug). When it happens, until i restart the application, reloadData never works again.
Update3:
I put self.dataSource==myExpectedViewController and also [self.dataSource tableView:self numberOfRowsInSection:0] to see if even delegates are not nil maybe they were being cloned etc.. The result was True and numberOfRows were correctly returning>0. So delegates are correct and i have more items than zero.
Update4:
I tried it with a fresh UITableView (removing my custom UITableView), i got the same results.
Update5:
I've put a button on the screen which recreates the table and sets its delegates. Whenever the problem in the question happens, i hit this button and everything starts to work perfectly. So, there must be something that breaks internals of UITableView which invalidates every call to reloadData, but i still couldn't find it.
Edited : I tried to replicate the issue and found, when I presented another viewcontroller on current view controller which has this tableview. and then 1. tried to reload this tableview with some data and 2. dismissed the viewcontroller which is on top of my currentviewcontroller with animation, simultaneously , then since in this duration, table view is not visible so it won't be reloaded.
To resolve, you can put a delay there or use completion block of that animation to reload table with effect.
Otherwise problem can be related to thread, UIElements are expected to be updated only on main thread.
During API calls and other process, we enters in other thread, and mostly we ignore to check whether we are on main thread before updating UIElement.
You should call yourTable.reloadData() in main thread using DispatchQueue.main.async{yourTable.reloadData()} and make sure it is being called on main thread.

Resources