Play audio From URL when click on a Button inside TableViewCell - uitableview

My tableView Method is
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
wordsTableViewCell *cell;
if (cell==nil)
{
cell=[tableView dequeueReusableCellWithIdentifier:#"cell"];
}
cell.wordIndexlbl.layer.masksToBounds = true;
cell.wordIndexlbl.layer.cornerRadius = 8;
cell.redWord.text= [self.wordsFromArray objectAtIndex:indexPath.row];
cell.blueWord.text=[self.words objectAtIndex:indexPath.row];
cell.wordIndexlbl.text=[self.wordsID objectAtIndex:indexPath.row];
cell.playCell.tag=indexPath.row;
[cell.playCell addTarget:self action:#selector(playURLCell:) forControlEvents:UIControlEventTouchUpInside];
return cell;
}
and then i make a button action and method to call function like this
- (IBAction)playURLCell:(UIButton *)sender
{
UIButton *senderButton=(UIButton *)sender;
NSLog(#"current row = %ld" , (long)senderButton.tag);
[self getWord:_uppercaseString For:_combinedStirng String:wordIndex];
}
-(void)getWord:(NSString*)upperCaseString For:(NSString *)combinedString String:(NSString *)wordIndex
{
BOOL isInternetAvailable = [[NetworkManager sharedInstance] check];
if (isInternetAvailable)
{
dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void){
NSData *data;
NSString *urlStr = [NSString stringWithFormat:#"http://quicklanguages.com/materiales/quicklanguages/audios/%#/%#-%#.mp3",upperCaseString,combinedString,wordIndex];
NSURL *url = [[NSURL alloc] initWithString:urlStr];
[playURLArray addObject:url];
data = [NSData dataWithContentsOfURL:url];
dispatch_async(dispatch_get_main_queue(), ^{
[self playAudio:data];
});
});
}
}
-(void)playAudio :(NSData *)data
{
audioPlayer = [[AVAudioPlayer alloc] initWithData:data error:nil]; // Now we are assigning it in an instance variable thus ARC will not deallocate it.
audioPlayer.delegate=self;
[audioPlayer play];
}
when I click on button inside from cell , audio not playing and wordIndex goes nill
no error comes what is the problem any one help me
please tell my problem

You have some conceptual errors in code.
I will give you some tips to work better.
a) at:
[cell.playCell addTarget:self action:#selector(playURLCell
You are adding an action to a cell OR to a button?
b) if you have a button, (as You did for other elements, as labels..) add action to it.
c) better to make a custom cell (I see you create a class "wordsTableViewCell", pls use WordsTableViewCell for classes..) AND load it from a separate XIB.
d) do not call dequeueReusableCellWithIdentifier conditionally if nil.. (see code Xcode creates for you for a new TableViewController)
simply use:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
WordsTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"cell" forIndexPath:indexPath];
// Configure the cell...
return cell;
}
e) make some preparation settings and action in "awakeFromNib":
#implementation WordsTableViewCell
- (void)awakeFromNib {
[super awakeFromNib];
// Initialization code
// set buttons or prepare labels... (or use action from IB..)
}
(labels will be filled up as You already do in cellForRowAtIndexPath)
f) better to use a protocol to let CONTROLLER play (or make the code inside custom code, in the action, but ugly (see below))
g) keep in mind cells are reused so you loose EVERYTHING you have setup when recycled.
h) last but NOT least:
code fails as in:
-(void)playAudio :(NSData *)data
{
audioPlayer = [[AVAudioPlayer alloc] initWithData:data error:nil]; // Now we are assigning it in an instance variable thus ARC will not deallocate it.
audioPlayer.delegate=self;
[audioPlayer play];
}
As audioPlayer will be released by ARC, so audio stops.
So you must KEEP an AVAudioPlayer instance alive: a viable solution is to put it in Controller.
Let's see the steps:
a) create a protocol, let's say
DidTapToPlayProtocol:
#protocol DidTapToPlayProtocol <NSObject>
#required
-(void)didTapToPlay:(NSInteger)tag;
#end
b)
in custom cell *.h (WordsTableViewCell.h) import protocol and declare a delegate:
#import "DidTapToPlayProtocol.h"
#interface WordsTableViewCell : UITableViewCell
#property (weak, nonatomic) id <DidTapToPlayProtocol>didTapDelegate;
#end
c) in controller, set delegate or cell:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
WordsTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"cell" forIndexPath:indexPath];
// Configure the cell...
cell.didTapDelegate = self;
return cell;
}
d) in button action call:
-(IBAction)play:(UIButton *)sender {
NSInteger tag ... // get tag..
[self.didTapDelegate didTapToPlay:tag];
}
e) in Table view controller *h allocate a data member:
#interface MyTableViewController : UITableViewController
#property (string, nonatomic) AVAudioPlayer* audioPlayer;
#end
and set it in delegate callback: (now will be retained. Note: we can use a better approach... allocating in in ViewDidLoad.. anyway..)
- (void)didTapToPlay:(NSInteger)tag{
NSData * data;
.....
self.audioPlayer = [[AVAudioPlayer alloc] initWithData:data error:nil];
}
(I have written a base code.. if need zip let me know..)

Related

How to filter the multiple selected values from an array and load it to other uitableview from a uibutton

I have 2 UiTableviews in a UiViewController. My exact requirement is to get the selected values from tableview1 and loaded to the tableview2 by tapping the Add Button.
I done Following at the moment
1. loaded JSON Responses to tableview1 (loaded the responses from a filepath at the moment) and printed to a custom nib cell
2. I can get the selected values to a response as follows
Next
3. I want to print that values to *cell2 from the selected values. Please explain the next steps in details.
Here is the UI
Main UI and Description
Here are the codes from table loading to selections.
Object - PSAData.h
#interface PSAData : NSObject
#property (nonatomic, strong) NSString *firstname;
#property (nonatomic, strong) NSString *lastname;
- (void)loadWithDictionary:(NSDictionary *)dict;
#end
Object - PSAData.m
#implementation PSAData
- (void)loadWithDictionary:(NSDictionary *)dict
{
self.firstname=[dict objectForKey:#"firstname"];
self.lastname=[dict objectForKey:#"lastname"];
}
table1 Viewcell - PSATableViewCell.h
#import <UIKit/UIKit.h>
#import "PSAData.h"
#import "NetworkConnectivityClass.h"
#interface PSATableViewCell : UITableViewCell
#property (nonatomic) NetworkConnectivityClass *networkConnectivityClassInstance;
-(void)loadWithData:(PSAData *)psaData;
#end
table1 viewcell - PSATableViewCell.m
#interface PSATableViewCell ()
#property (strong, nonatomic) IBOutlet UILabel *firstnameLbl;
#property (strong, nonatomic) IBOutlet UILabel *lastnameLbl;
#end
#implementation PSATableViewCell
- (void)awakeFromNib {
[super awakeFromNib];
// Initialization code
}
- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
[super setSelected:selected animated:animated];
}
-(void)loadWithData:(PSAData *)psaData
{
[self methodSetupText:psaData];
}
-(void)methodSetupText:(PSAData *)psaData
{
self.firstnameLbl.text=psaData.firstname;
self.lastnameLbl.text=psaData.lastname;
}
#end
Main View Controller - PersonnelViewController
- (void)viewDidLoad {
[super viewDidLoad];
// NSMutableArray *selectedArray=[[NSMutableArray alloc]init];
tableView1.dataSource =self;
tableView1.delegate=self;
tableView2.dataSource=self;
tableView2.delegate=self;
//initializing arrays for get selected values
self.selectedCells=[NSMutableArray array];
self.selectedPSAData=[NSMutableArray array];
//loading web resonse data
self.loadedPSAData=[[NSMutableArray alloc]init];
NetworkConnectivityClass *networkConnectivityClassInstance = [NetworkConnectivityClass new];
__weak PersonnelViewController *weakVersionOfSelf=self;
[networkConnectivityClassInstance methodReturnTableViewMessages:^(NSMutableArray *returnedArrayWithMessages)
{
weakVersionOfSelf.loadedPSAData=returnedArrayWithMessages;
[weakVersionOfSelf.tableView1 reloadData];
}];
//register left side tableview cell (Assigned tableview1)
[self.tableView1 registerNib:[UINib nibWithNibName:#"PSATableViewCell" bundle:nil] forCellReuseIdentifier:#"PSATableViewCell"];
}
//tableview Delegates
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
if(tableView ==self.tableView1)
{
return 1;
}
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
if(tableView==self.tableView1)
{
return self.loadedPSAData.count;
}
return self.loadedPSAData.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
//loading table data into cell tableview1 and tableview2
static NSString *cellIdentifier=#"PSATableViewCell";
PSATableViewCell *cell=[tableView1 dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell==nil) {
cell=[[PSATableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"PSATableViewCell"];
}
//tableview2 implementation
static NSString *cellIdentifier2=#"PSSITableViewCell";
PSSITableViewCell *cell2=[tableView2 dequeueReusableCellWithIdentifier:cellIdentifier2];
if (cell2==nil) {
cell2=[[PSSITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"PSSITableViewCell"];
}
cell.accessoryType = ([self isRowSelectedOnTableView:tableView1 atIndexPath:indexPath]) ? UITableViewCellAccessoryCheckmark : UITableViewCellAccessoryNone;
if(tableView == self.tableView1)
{
[cell loadWithData:[self.loadedPSAData objectAtIndex:[indexPath row]]];
}
else if(tableView == self.tableView2)
{
[cell2 loadWithDataS2:[self.loadedPSAData objectAtIndex:[indexPath row]]];
return cell2;
}
return cell;
}
pragma mark - multiple selection
- (void)tableView:(UITableView *)tableView
didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSString *psaData =[self.loadedPSAData objectAtIndex:indexPath.row];
PSATableViewCell *cell=[tableView1 cellForRowAtIndexPath:indexPath];
NSString *sampleAH =[self.selectedPSAData description];
if([self isRowSelectedOnTableView:tableView1 atIndexPath:indexPath])
{
[self.selectedCells removeObject:indexPath];
[self.selectedPSAData removeObject:psaData];
cell.accessoryType =UITableViewCellAccessoryNone;
}
else{
[self.selectedCells addObject:indexPath];
[self.selectedPSAData addObject:psaData];
cell.accessoryType =UITableViewCellAccessoryCheckmark;
}
NSLog(#"%#", self.selectedPSAData);
sampleArrayholder.text=[NSString stringWithFormat:#"%#", sampleAH];
}
-(BOOL)isRowSelectedOnTableView:(UITableView *)tableView atIndexPath:(NSIndexPath *)indexPath
{
return ([self.selectedCells containsObject:indexPath]) ? YES : NO;
}
**Finally NetworkConnectivity class - NetworkConnectivityClass.h **
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#import "WorksitenameList.h"
#interface NetworkConnectivityClass : NSObject
-(void)methodLogin:(NSString *)stringToLogin withUserName:(NSString *)stringUsername withPassword:(NSString *)stringPassword completion:(void(^)(NSDictionary *))completion;
-(void)methodReturnTableViewMessages:(void (^)(NSMutableArray *))completion;
-(NSURLSessionTaskState)methodCheckIfSessionIsRunning;
-(void)methodCancelNetworkRequest;
#end
**Finally NetworkConnectivity class - NetworkConnectivityClass.m **
-(void)methodReturnTableViewMessages:(void (^)(NSMutableArray *))completion
{
dispatch_queue_t queueForJSON = dispatch_queue_create("queueForJSON", NULL);
dispatch_async(queueForJSON, ^{
NSString *filePath = [[NSBundle mainBundle] pathForResource:#"PSAData" ofType:#"json"];
NSError *error = nil;
NSData *rawData = [NSData dataWithContentsOfFile:filePath options:NSDataReadingMappedIfSafe error:&error];
id JSONData = [NSJSONSerialization JSONObjectWithData:rawData options:NSJSONReadingAllowFragments error:&error];
NSMutableArray *loadedPSAData = [NSMutableArray new];
[loadedPSAData removeAllObjects];
if([JSONData isKindOfClass:[NSDictionary class]])
{
NSArray *loadedArray=[JSONData objectForKey:#"records"];
if([loadedArray isKindOfClass:[NSArray class]])
{
for(NSDictionary *psaDict in loadedArray)
{
PSAData *psaData=[[PSAData alloc]init];
[psaData loadWithDictionary:psaDict];
[loadedPSAData addObject:psaData];
}
}
}
dispatch_async(dispatch_get_main_queue(), ^{
completion(loadedPSAData);
NSLog(#"test: %#", loadedPSAData);
});
});
}
I Added All the required codes to have a look at it. Since I am relatively new to iOS Dev. Please Write a codes / instructions step by step clearly to save some time :).
**Please Note : At the moment I loaded the same tableview1 data to tableview2 *cell2 But I want here to load the selected values(Multiple Selection). from tableview1 loadedPSAData Array to load in table view to by tapping an Add Button. Finally sorry for my poor English ;) **
Suppose these 2 are your table outlet.
__weak IBOutlet UITableView * myTable1;
__weak IBOutlet UITableView * myTable2;
You set the Delegate and Data Source like below in your viewDidLoad
myTable1.delegate=self;
myTable1.dataSource=self;
myTable2.delegate=self;
myTable2.dataSource=self;
Now These are 2 Arrays
array1 ==> Which contain All Data
arraySelectedValues ==> Which contain you selected data
So you use this like below
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if(self.myTable1 == tableView)
{
return [array1 count];
} else {
return [arraySelectedValues count];
}
}
As I review your Code, Your problem may be in CellForRow. Why to create 2 separate cells, when there is same CellIdentifier. You just need to change the Data.
You should create 2 cells only When Both Tableview are using Diff-Diff tableviewcells. In your case you are using same cell.
Try to modify the code like this
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *cellIdentifier=#"PSATableViewCell";
PSATableViewCell *cell=[tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell==nil) {
cell=[[PSATableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier: cellIdentifier];
}
if(tableView == myTable1)
{
[cell loadWithData:[array1 objectAtIndex:[indexPath row]]];
}
else if(tableView == myTable2)
{
[cell loadWithData:[arraySelectedValues objectAtIndex:[indexPath row]]];
}
return cell;
}
didSelectRowAtIndexPath should look like :
- (void)tableView:(UITableView *)tableView
didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
if(tableView == myTable1)
{
// Your code for highlighting
} else {
// This will be you myTable2 did select click.
}
}
Just When ever you want to refresh the record, you should to Call ReloadData method For respective Tableviews.
Hope you understand how you load the data in 2 Tableviews in Single ViewController.

Passing parameters from UITableViewCell to UITableView (Dynamic Content)

How might I pass my objects via parameters from my custom UITableViewCell class to my UITableView. Because I'm using Dynamic Prototype Cells, I can't assign my objects to the textviews within the cells. For this reason I need to pass my objects from class to class.
MainTableViewController.m
- (void)viewDidLoad
{
[super viewDidLoad];
NSURL *myURL = [[NSURL alloc]initWithString:#"http://domain.com/json2.php"];
NSData *myData = [[NSData alloc]initWithContentsOfURL:myURL];
NSError *error;
NSArray *jsonArray = [NSJSONSerialization JSONObjectWithData:myData options:NSJSONReadingMutableContainers error:&error];
if(!error)
{
for (NSDictionary * needs in jsonArray)
{
textNeedTitle.text = [needs objectForKey: #"needTitle"];
textNeedPoster.text = [needs objectForKey: #"needPoster"];
textNeedDescrip.text = [needs objectForKey: #"needDescrip"];
}
}
else
{
textNeedTitle.text = [NSString stringWithFormat:#"Error--%#",[error description]];
}
return cell;
// Uncomment the following line to preserve selection between presentations.
// self.clearsSelectionOnViewWillAppear = NO;
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
// self.navigationItem.rightBarButtonItem = self.editButtonItem;
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
return 3;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Cell" forIndexPath:indexPath];
}
TestTableViewCell.h
#import <UIKit/UIKit.h>
#interface TestTableViewCell : UITableViewCell
#property (weak, nonatomic) IBOutlet UITextView *textNeedTitle;
#property (weak, nonatomic) IBOutlet UITextView *textNeedPoster;
#property (weak, nonatomic) IBOutlet UITextView *textNeedDescrip;
Each of the properties above are assigned via a Referencing Outlet to it's appropriate UITextView.
I'm not entirely sure what you're trying to do, but I noticed that in your UITableViewController you're getting a UITableViewCell instead of your custom class TestTableViewCell.
It should be like:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
TestTableViewCell *cell = (TestTableViewCell *) [tableView dequeueReusableCellWithIdentifier:#"Cell" forIndexPath:indexPath];
}
Make sure that:
* In the storyboard, the reuse identifier of the cells is "Cell" (or a more appropriate name...)
* The class for the prototype cells is TestTableViewCell
Then you should be able to access the properties of the cell, like cell.textNeedTitle.text = #"Something"

UITableView reloadData doesn't work when change sub object in datasoure.

There are 5 objects in datasoure for example,if the first object is like this:
Obj -> id:1,name:"A"
when I change the object's name to "B";
Obj -> id:1,name:"B"
then [tableView reloadData]
the first cell still display "A",I want to change it to "B".
In the cellForRowAtIndexpath method manage the datasource method properly as it retrives the value from the datasource array and displays it,That is it
I doubt the problem is that the reusability is causing the trouble in your code
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell;
static NSString *cellIdentifier1 = #"surveyCell";
if (tableView== self.surveytableView) {
cell= [tableView dequeueReusableCellWithIdentifier:cellIdentifier1];
if(cell==nil)
{
//alloc the cell
//DO NOT SET THE VALUE HERE
}
//here set the value
return cell;
}
here is the code, what i did was,
created a class called "DataClass" which provides data for your tableview
created objects like you mentioned , i stored it in an array("dataSource")
after that i loaded it to tableview (i assume u are properly wired up tableview datasource and delegate)
I put a button to make change the string in the datasource array.
button's action is connected to method and within that i am reloading the tableview
//class DataClass
#interface DataClass : NSObject
{
#public;
NSString *str;
}
#implementation DataClass
- (id)init
{
[super init];
str = nil;
return self;
}
#end
//viewController.h
#interface ViewController : UIViewController<UITableViewDataSource ,UITableViewDelegate>
{
IBOutlet UITableView *aTableView;
IBOutlet UIButton *aButton;
}
- (IBAction)whenButtonClicked:(id)sender;
#end
//in .m file
#import "ViewController.h"
#import "DataClass.h"
#interface ViewController ()
{
NSMutableArray *DataSource;
}
#end
// ViewController.m
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
aTableView.dataSource = self;
aTableView.delegate = self;
DataSource = [[NSMutableArray alloc]init];
for(int i=0 ; i<5 ; i++)
{
DataClass *data = [[DataClass alloc]init];
data->str=#"hello";
[DataSource addObject:data];
[data release];
}
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *aCell = [tableView dequeueReusableCellWithIdentifier:#"Cell"];
if(aCell == nil)
{
aCell = [[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"Cell"]autorelease];
}
DataClass *aValue = [DataSource objectAtIndex:indexPath.row];
aCell.textLabel.text = aValue->str;
return aCell;
}
- (IBAction)whenButtonClicked:(id)sender
{
DataClass *aObj = [DataSource objectAtIndex:2];//changing the 3'rd object value as yours in 5th object
aObj->str = #"world";
[aTableView reloadData];
}
#end
//after "changeValue" button pressed the third row displays "world"

Pass data back to parent controller for iOS development

i have problem to display selected data into detaillabeltext in one of my row of section, beside reload the whole table view any other method to reload only certain row of section?
//RootViewController.m (parent controller)
-(void) selectedData:(NSString*) text
{
selectedAbsenceType = text;
NSLog(#"the absence type select is %#",text);
}
-(void) (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
if (indexPath.section == 0)
{
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}
}
NSDictionary *dictionary = [dataArray objectAtIndex:indexPath.section];
NSArray *array = [dictionary objectForKey:#"data"];
NSString *cellValue = [array objectAtIndex:indexPath.row];
cell.textLabel.text = cellValue;
if([cellValue isEqual: #"Absence Type"])
{
cell.detailTextLabel.text = selectedAbsenceType;
}
else if([cellValue isEqual:#"Start Date"])
{
cell.detailTextLabel.text = selectedDate;
}
return cell;
}
===========================================================================================
i have a problem when i calling the method of the protocol, it keep prompt me a ARC Semantic Issue at this statement
[self.delegate selectedData: (NSString*) [self.absenceTypes objectAtIndex:indexPath.row]];:
//child.h
#import <UIKit/UIKit.h>
#protocol childViewControllerDelegate;
#interface AbsenceTypesViewController : UITableViewController
{
id<childViewControllerDelegate>delegate;
}
#property (nonatomic,weak) id<childViewControllerDelegate> delegate;
#property NSArray *absenceTypes;
#end
#protocol childViewControllerDelegate <NSObject>
-(void) selectedData:(NSString*) text;
#end
//child.m
#pragma mark - Table view delegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *selectedCell = nil;
selectedCell = [self.absenceTypes objectAtIndex:indexPath.row];
[self.delegate selectedData: (NSString*) [self.absenceTypes objectAtIndex:indexPath.row]];
//[self.navigationController popViewControllerAnimated:YES];
NSLog(#"%#", selectedCell);
}
Remove {
id<childViewControllerDelegate>delegate;
} inside user class interface.id<childViewControllerDelegate>delegate; means strong variable which will be released only when holding object is released. But in property declaration you are mentioning delegate as weak property. Hence the ARC Semantic is giving you warning. You can also make the delegate weak by declaring it as weak explicitly like __weak id<childViewControllerDelegate>delegate;
Try replacing the .h file content with this.
#import <UIKit/UIKit.h>
#class AbsenceTypesViewController;
#protocol childViewControllerDelegate <NSObject>
-(void) selectedData:(NSString*) text;
#end
#interface AbsenceTypesViewController : UITableViewController
{
id<childViewControllerDelegate>delegate;
}
#property (nonatomic,weak) id<childViewControllerDelegate> delegate;
#property NSArray *absenceTypes;
#end
So that you have forward declaration of class.
You can save all selected option of second view controller in NSMutable Array and save all components separated by comma and send this array to your parent controller.
NSMutableArray *selectedVal =[[NSMutableArray alloc] init];
FirstViewController *FVC = (FirstViewController*)
if ([FVC isKindOfClass:[FirstViewController class]])
{
[FVC setSelectedOption:[selectedVal componentsJoinedByString:#","]];
}
[self.navigationController popViewControllerAnimated:YES];

Display multiple uiwebviews in uitablview

I encountered a problem of webview and I thin many people had met that.
In my app, I have an UITableview and each cell of the tableview is self-defined. In each cell a UIWebview is embedded. I need to display each cell's content when I scroll my tableview. (webview's loadsHTML and image_url is from an local array)
Problem is that the UIWebview in each cell loads a remote image url and when user scrolls so fast the table, the webview in the cell can not reac fast enough so the webview may display the repeated image for less than 1 second. (Since I use reusable cell and webview loads from image_url array, so that
image_url = [array_image_url objectAtIndex:[index row]];
For user experience, that is terrible to see the repeated images. I tries to figue it out but still can't. Can anyone help me on this issue?
PS: If possible, I don't want to cache image on disk
I have had a similar problem (I was displaying remote images) and used the UIScrollView delegate methods (UITableView inherits from UIScrollView) to handle when to update my images or not. You can do something similar to load content when the scrolling is stopped:
// UIScrollView Delegate Methods
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate {
if (!decelerate) {
[self loadImagesForOnscreenRows];
}
}
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
[self loadImagesForOnscreenRows];
}
EDIT - Forgot the method that actually loads the rows. This might help :)
Note - Some of this code is specific to my app, you will need to adapt to suit your data and web location of the image. Also - the setImageWithURL method is part of the AFNetworking library. If you haven't checked out AFNetworking, it rocks. If you aren't already using AFN and don't need to, then I also added a class I wrote that uses blocks to async load web images.
- (void)loadImagesForOnscreenRows
{
if ([self.phonebookData count] > 0)
{
NSArray *visiblePaths = [self.myTableView indexPathsForVisibleRows];
for (NSIndexPath *indexPath in visiblePaths)
{
NSDictionary *selRow = [[self.persons valueForKey:[[[self.persons allKeys] sortedArrayUsingSelector:#selector(localizedCaseInsensitiveCompare:)] objectAtIndex:indexPath.section]] objectAtIndex:indexPath.row];
PBCell *cell = (PBCell *)[self.myTableView cellForRowAtIndexPath:indexPath];
if ([[selRow objectForKey:#"picFileName"] length] > 0) {
[cell.thumbnailImage setImageWithURL:[NSURL URLWithString:[NSString stringWithFormat:#"YourURLHere/%#",[selRow objectForKey:#"picFileName"]]] placeholderImage:[UIImage imageNamed:#"placeholder.png"]];
} else {
cell.thumbnailImage.image = [UIImage imageNamed:#"defaultImage.png"];
}
}
}
}
Alternative method instead of AFNetworking:
WebImageOperations.h:
//
// WebImageOperations.h
//
// Created by Larry Wilson on 11/11/11.
// Copyright (c) 2011 Larry Wilson. All rights reserved.
//
#import <Foundation/Foundation.h>
#interface WebImageOperations : NSObject {
}
+ (void)processImageDataWithURLString:(NSString *)urlString andBlock:(void (^)(NSData *imageData))processImage;
#end
WebImageOperations.m:
//
// WebImageOperations.m
//
// Created by Larry Wilson on 11/11/11.
// Copyright (c) 2011 Larry Wilson. All rights reserved.
//
#import "WebImageOperations.h"
#import <QuartzCore/QuartzCore.h>
#implementation WebImageOperations
+ (void)processImageDataWithURLString:(NSString *)urlString andBlock:(void (^)(NSData *imageData))processImage
{
NSURL *url = [NSURL URLWithString:urlString];
dispatch_queue_t callerQueue = dispatch_get_current_queue();
dispatch_queue_t downloadQueue = dispatch_queue_create("com.myappname.processimagedataqueue", NULL);
dispatch_async(downloadQueue, ^{
NSData * imageData = [NSData dataWithContentsOfURL:url];
dispatch_async(callerQueue, ^{
processImage(imageData);
});
});
dispatch_release(downloadQueue);
}
#end
Multiple UIWebViews in UITableView is not a good practice.But sometimes we wanna build an app in a short time,UIWebView is a very convenient class for us.
In my case,I set a custom UITableViewCell
CustomTableViewCell.h
#import <UIKit/UIKit.h>
#interface VerticalTableViewCell : UITableViewCell
#property (nonatomic,retain) UIWebView * webView;
-(void)setWebViewContent:(NSString *)htmlContent andIndex:(NSString *)row;
#end
CustomTableViewCell.m
#import "CustomTableViewCell.h"
#interface CustomTableViewCell()
#end
#implementation VerticalTableViewCell
#synthesize webView;
- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:reuseIdentifier];
if (self) {
self.webView = [[UIWebView alloc]init];
[self.webView setFrame:self.contentView.frame];
[self.webView setUserInteractionEnabled:NO];
[self.contentView addSubview:self.webView];
}
return self;
}
-(void)setWebViewContent:(NSString *)htmlContent andIndex:(NSString *)row
{
[self.webView loadHTMLString:[NSString stringWithFormat:#"<html><head></head><body><div style='width:414px;height:414px;background-image:url(%#);background-size:414px 414px;'></div><p>现在是第%#排</p></body></html>",htmlContent,row] baseURL:nil];
}
- (void) layoutSubviews
{
[super layoutSubviews];
CGRect contentViewFrame = self.contentView.frame;
contentViewFrame.size.width = [[UIScreen mainScreen] bounds].size.width;
contentViewFrame.size.height = 586.0f;
self.contentView.frame = contentViewFrame;
self.webView.frame = contentViewFrame;
}
-(void)dealloc
{
[self.webView loadHTMLString:nil baseURL:nil];
self.webView = nil;
}
#end
CustomTableView.m
...
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CMainCell = #"CMainCell";
CustomTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CMainCell];
if (cell == nil) {
cell = [[CustomTableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier: CMainCell];
//自定义cell的内容
}
if (self.whiteData!=nil) {
NSString * row = [NSString stringWithFormat:#"%ld",indexPath.row];
[cell setWebViewContent:self.whiteData[indexPath.row] andIndex:row];
//[cell setCustomImage:self.whiteData[indexPath.row]];
}
return cell;
}
-(void)tableView:(UITableView *)tableView didEndDisplayingCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
CustomTableViewCell * customCell = (CustomTableViewCell *)cell;
[customCell.webView loadHTMLString:nil baseURL:nil];
}
...
You can see I used the method :
-(void)tableView:(UITableView *)tableView didEndDisplayingCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath;
In this method,when the cell invisible in tableView,cells will set webViews empty.
In our cases,because of the UITableView Reuse feature,cells won't clean up the contentViews.Therefore users scroll tableView in a very fast way,the cells would be reused and the HTML content is still there.If we clean up the contentView,works well.
But another problem is still here.Because cells should render HTML content when they come into visible area.Rendering speed of UIWebView is not quite fast,so we should write some code for optimizing the rendering process.
Hope this would help you.Cheers.

Resources