how to use block replace common delegate - ios

A class:
In following method, I use blocks to replace common delegate. Is it ok? The block in the didSelectRowAtIndexPath method, I use it replace common delegate, but if it run, I click the table cell and the code crashes.
typedef void (^Block)(NSString *id,NSString *cityName);
#interface WLCCityListViewController : WLCBaseSquareViewController <UITableViewDataSource,UITableViewDelegate>
{
Block _block;
id<commonDelegate>delegate;
}
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil Block:(Block)block
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
_block=block;
}
return self;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
WLCMainViewCityListData *data=[[self citylists]objectAtIndex:[indexPath section]];
// [self.delegate seleteCityID:[[data.cityList objectAtIndex:indexPath.row]objectForKey:#"id"] CityName:[[data.cityList objectAtIndex:indexPath.row]objectForKey:#"name"]];
NSString *a1 =[[data.cityList objectAtIndex:indexPath.row]objectForKey:#"id"];
NSString *a2 =[[data.cityList objectAtIndex:indexPath.row]objectForKey:#"name"];
_block(a1,a2);
}
B class:
#interface WLCMainViewController : WLCBaseSquareViewController
{
}
#implementation WLCMainViewController
-(void)viewDidLoad {
WLCCityListViewController *tableViewController = [[[WLCCityListViewController alloc]initWithNibName:#"WLCCityListViewController" bundle:nil Block:^(NSString *id, NSString *cityName) {
self.cityID=id;
WLCMainViewModel *model=(WLCMainViewModel *)self.mainviewModel;
model.cityID=id;
[model sendRequest];
[self.view startWaiting];
}] autorelease];
}

_block = block;
This line makes the crash. you just assign a block but doesn't keep it.DON'T USE retain,only use copy.
declare a copy property.
#property (nonatomic, copy) Block _block;
and use setter. or just change you code like this.
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil Block: (Block)block
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
//_block=block;
_block = block? [[block copy] autorelease]: nil;
}
return self;
}

You can consider the block as a OC object.
Generally if you need to keep the block, use Block_copy to do so and don't forget to Block_release it.
The problem of your code is that the block is autoreleased when you call it.

Related

How to pass value from subclass to super class during initialization

Suppose, I've two view controller. ViewController1 is the sub class of ViewController2. From subclass (ViewController1), I called superclass init method & passed a value by parameter & assigned that value to the superclass variable. But In superclass (ViewController2)'s viewDidLoad method, that value is always null. Why ? How can I pass that value from sub to super so that I can get that value in super class's viewDidLoad method ?
ViewController1.h
#interface ViewController : ViewController2
#end
ViewController1.m
#implementation ViewController
- (instancetype)init
{
self = [super initWithName:#"Hello"];
if (self) {
NSLog(#"1 :");
}
return self;
}
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
ViewController2.h
#interface ViewController2 : UIViewController
#property (nonatomic, strong) NSString *name;
-(instancetype)initWithName:(NSString *)name;
#end
ViewController2.m
- (instancetype)initWithName:(NSString *)name
{
self = [super init];
if (self) {
self.name = name;
}
return self;
}
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
NSLog(#"2 : %#", self.name);
}
#end
I tired your code and it worked just fine. I suspect, that you don't instantiate your ViewController directly. Do you use storyboard in your project? If yes - you should override initWithCoder: in ViewController.
However, it is bad idea to set any properties of view controllers during init-family methods. According to Apple recommendations, all customisation should be done in -viewDidLoad or -viewWill/DidAppear methods.
If you absolutely in need to set name property from outside, it is better you assign it directly, not trough passing argument to init method.
One more thing - initWithNibName:bundle: is Designated initializer. It means, that your subclasses absolutely must in the end call it during initialisation chain.
Updated - 16-Mar-2016
Example :
ViewController1.h
#import <UIKit/UIKit.h>
#import "ViewController2.h"
#interface ViewController1 : ViewController2
#end
ViewController1.m
#import "ViewController1.h"
#interface ViewController1 ()
#end
#implementation ViewController1
-(instancetype)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
//self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil andUserName:#"Ramesh Annadurai"];
// we can use above init method or below method, both will work
self = [super initWithName:#"Test Name"];
if (self) {
[self.view setBackgroundColor:[UIColor brownColor]];
}
return self;
}
-(instancetype)initWithCoder:(NSCoder *)aDecoder
{
//self = [super initWithCoder:aDecoder];
// If you are using storyboard use this initWithCoder method.
self = [super initWithName:#"Test Name"];
if (self) {
}
return self;
}
- (void)viewDidLoad {
[super viewDidLoad];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
#end
ViewController2.h
#import <UIKit/UIKit.h>
#interface ViewController2 : UIViewController
- (instancetype)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil andUserName:(NSString *) userName;
- (instancetype)initWithName:(NSString *) userName;
#end
ViewController2.m
#import "ViewController2.h"
#interface ViewController2 ()
#property (strong, nonatomic) NSString *userName;
#end
#implementation ViewController2
- (instancetype)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil andUserName:(NSString *) userName
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
self.userName = userName;
}
return self;
}
- (instancetype)initWithName:(NSString *) userName
{
self = [super initWithNibName:nil bundle:nil];
if (self) {
self.userName = userName;
}
return self;
}
- (void)viewDidLoad {
[super viewDidLoad];
NSLog(#"User Name : %#", self.userName);
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
#end

How to pass a variable between UIViewControllers

I have a Detail View Controller which contains data passed from a Table View:
#import "BRProjectsDetailViewController.h"
#interface BRProjectsDetailViewController ()
#end
#implementation BRProjectsDetailViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (IBAction)unwindBackToProjectsDetailViewController:(UIStoryboardSegue *)seque;
{
NSLog(#"unwindBackToHomeViewController!");
}
///used to feed data from homeview into detail view
-(void) viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
NSLog(#"viewWillAppear");
NSString *name = self.projects[#"name"];
self.title = name;
NSString *description = self.projects[#"description"];
self.descriptionView.text = description;
}
I want to take the variable string labelled 'name' above and pass the contents of this to a collection view controller, currently coded below. At the moment, before doing conditioning I'm just trying to get a response from my NSLog. Currently it just returns null: . This is just an excerpt from the code: Can anyone help please?
#import "BRCollectionViewController.h"
#import "BRCollectionViewCell.h"
#import "BRProjectsDetailViewController.h"
#interface BRCollectionViewController ()
{
///add arrays for photos - to update once photos known
NSArray *imagesOne;
NSArray *imagesTwo;
}
#end
#implementation BRCollectionViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad {
//added this
NSString *name;
NSLog(#"%#", name);
//
}
#end

accessing class property which is added by frord declaration from another class

I have a class
#interface AppRecord : NSObject
#property (nonatomic, retain) NSString * urlSingle;
#property (nonatomic, retain) NSArray * image_url;
#end
It is included in another class
#class AppRecord;
#interface IconDownloader : NSObject
#property (nonatomic, strong) AppRecord *appRecord;
#end
This is my root view controller
#import "IconDownloader.h"
#implementation RootViewController
- (void)viewDidLoad
{
[super viewDidLoad];
self.imageDownloadsInProgress = [NSMutableDictionary dictionary];
}
- (void)startIconDownload:(AppRecord *)appRecord forIndexPath:(NSIndexPath *)indexPath
{
IconDownloader *iconDownloader = [self.imageDownloadsInProgress objectForKey:indexPath];
if (iconDownloader == nil)
{
iconDownloader = [[IconDownloader alloc] init];
int imgArrCount=[appRecord.image_url count];
NSLog(#"Image array is********************** %#",appRecord.image_url);
for(int i=0;i<imgArrCount;i++)
{
iconDownloader.appRecord.urlSingle=[appRecord.image_url objectAtIndex:i];
NSLog(#"iconDownloader.appRecord.urlSingle---------------------%#",iconDownloader.appRecord.urlSingle);
}
}
}
#end
Can i assign iconDownloader.appRecord.urlSingle here, I am having null value.Please help.
This has nothing to do with forward declaration. When you forward declare a class, you should #import the .h file before using any of the class properties/methods.
The problem is property appRecord in iconDownloader is not created yet and hence is nil. In your code you should do this.
- (void)startIconDownload:(AppRecord *)appRecord forIndexPath:(NSIndexPath *)indexPath
//...
for(int i=0;i<imgArrCount;i++)
{
// First assign to the property so that it is not nil
iconDownloader.appRecord = appRecord;
// If required then make this assignment
iconDownloader.appRecord.urlSingle=[appRecord.image_url objectAtIndex:i];
}
//...
}
Alternately, you can also override the init in IconDownloader class and create the appRecord property inside it, so that it is not nil when you are assigning values.
Hope that helps!
You didnt initializing the appRecord object. thats why you get null value. Just initialize appRecord in your init method like:
-(id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
appRecord = [[AppRecord alloc]init];
}
return self;
}
Similiarly you have to initialize the urlSingle variable inside the init definition:
-(id)init
{
self = [super init];
if (self) {
urlSingle = URL_STRING_HERE;
}
return self;
}
Now you try

cannot set the text of label in DetailViewController after passing data between different viewController

pass data from FirstViewController to DetailViewController. i can not set the text of label in DetailViewController; FirstViewController is a tableview and it is good.
i use method updateRowNumber to set the rowNumber . and in DetailViewController, i can use debugger to see the rowNumber is correct. but the label's text is not showed on the view.
anyone can help me out?
in my FirstViewController
- (void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if (dvController == nil)
{
DetailViewController *aController = [[DetailViewController alloc] initWithNibName:#"DetailViewController" bundle:nil];
self.dvController = aController;
[aController release];
}
[[self navigationController] pushViewController:dvController animated:YES];
[dvController updateRowNumber:indexPath.row];
}
in my DetailViewController.h
#import <UIKit/UIKit.h>
#interface DetailViewController : UIViewController
{
int rowNumber;
IBOutlet UILabel *message;
}
#property(readwrite) int rowNumber;
#property(nonatomic, retain) IBOutlet UILabel *message;
- (void) updateRowNumber:(int) theindex;
#end
in my DetailViewController.m
#import "DetailViewController.h"
#interface DetailViewController ()
#end
#implementation DetailViewController
#synthesize message, rowNumber;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void) updateRowNumber: (int) theindex
{
rowNumber = theindex + 1;
message.text = [NSString stringWithFormat:#"row %i was clicked", rowNumber];
}
- (void)dealloc
{
[message release];
[super dealloc];
}
- (void)viewDidLoad
{
message.text = [NSString stringWithFormat:#"row %i was clicked ", rowNumber];
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Do any additional setup after loading the view from its nib.
}
- (void)viewWillAppear:(BOOL)animated
{
//message.text = [NSString stringWithFormat:#"row %i was clicked ", rowNumber];
[super viewWillAppear: animated];
}
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear: animated];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
You'll need to learn how the view is loaded, the process is well described in the documentation
What happens is that the view and all the outlets are nil until the view is loaded, you can make sure it is loaded by calling self.view; before configuring the outlet at updateRowNumber:
Please also note, you are better to call [super viewDidLoad] in the beginning of the overridden viewDidLoad, it makes sense as you need to let UIViewContorller to do it's staff before you do some customized logic, the dealloc is different as you need to do your logic before the standard NSObject -dealloc fires. Hope it's understandable.

Why the value does not pass to next TabbarViewController?

In one.m
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSUInteger row = [indexPath row];
NSString *carNumber = [self.carNumberArrayFromPlistFile objectAtIndex:row];
NSString *engineNumber = [self.engineNumberArrayFromPlistFile objectAtIndex:row];
CarInfo *oneCarInfo = [[CarInfo alloc] initWithCarNumber:carNumber engineNumber:engineNumber];
Two *two = [[Two alloc] initWithNibName:#"Two" bundle:nil];
two.car = oneCarInfo;
[self.navigationController pushViewController:two animated:YES];
[oneCarInfo release];
[two release];
}
In two.h
#interface Two : UITabBarController
{
CarInfo *car;
}
#property (nonatomic, retain)CarInfo *car;
And why the car in Two.m is always null? Please help me with this. Thank you guys!
Two.m:
#interface Two ()
#end
#implementation Two
#synthesize car;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
}
- (void)viewDidUnload
{
[super viewDidUnload];
self.car = nil;
}
- (void)dealloc
{
[super dealloc];
}
#end
#PeterPajchl : you are not supposed to push instance of UITabBarController onto the stack of UINavigationController - check the documentation.

Resources