How to implement initWith method passing custom object as an argument? - objective-c

For instance I have following class:
#interface PrivateInfo: NSObject
- (instancetype)initWithPrivateInfoObject:(PrivateInfo *)pi;
#end
#implementation PrivateInfo
{
#private
NSString *name;
NSString *creditCardID;
}
- (instancetype)initWithPrivateInfoObject:(PrivateInfo *)pi
{
// how to init current object with passed pi ?
}
- (PrivateInfo *)copy
{
// how to create a copy of current object?
}
#end

Assuming ARC:
.h:
#interface PrivateInfo: NSObject <NSCopying>
- (instancetype)initWithPrivateInfoObject:(PrivateInfo *)pi;
#end
.m:
#implementation PrivateInfo {
NSString *name;
NSString *creditCardID;
}
- (instancetype)initWithPrivateInfoObject:(PrivateInfo *)pi
{
self = [super init];
if (self) {
name = pi->name;
creditCardID = pi->creditCardID;
}
return self;
}
- (PrivateInfo *)copyWithZone:(NSZone *)zone {
PrivateInfo *res = [[PrivateInfo alloc] initWithPrivateInfoObject:self];
return res;
}
#end
You don't need #private in the #implementation block for declaring ivars. And use the NSCopying protocol is you want to copy objects.

Related

Property not found although it should be

This is a weird bug.
I have this in the header:
#import "UIKit/UIKit.h"
#interface ProxyProfileObject : NSObject <NSCoding> {
NSString *profileName;
NSString *ipAddress;
NSString *port;
}
-(void) setProfileName:(NSString *)string;
-(NSString*) getProfileName;
-(void) setIP:(NSString *)string;
-(NSString*) getIP;
-(void) setPort:(NSString *)string;
-(NSString*) getPort;
#end
And this in the implementation:
#import "ProxyProfileObject.h"
#interface ProxyProfileObject()
#end
#implementation ProxyProfileObject
-(void) setProfileName:(NSString *)string{
profileName = string;
}
-(NSString*) getProfileName{
return profileName;
}
-(void) setIP:(NSString *)string{
ipAddress = string;
}
-(NSString*) getIP{
return ipAddress;
}
-(void) setPort:(NSString *)string{
port = string;
}
-(NSString*) getPort{
return port;
}
// Encoding stuff
- (id)initWithCoder:(NSCoder *)decoder {
if (self = [super init]) {
self.profileName = [decoder decodeObjectForKey:#"profileName"];
self.port = [decoder decodeObjectForKey:#"port"];
self.ipAddress = [decoder decodeObjectForKey:#"ip"];
}
return self;
}
- (void)encodeWithCoder:(NSCoder *)encoder {
[encoder encodeObject:profileName forKey:#"profileName"];
[encoder encodeObject:ipAddress forKey:#"ip"];
[encoder encodeObject:port forKey:#"port"];
}
#end
I am not sure why it does this. It shouldn't do it as ipAddress is the same thing as port or profile name.
Those are the two files. You can now see by yourself how ipAddress doesn't work.
In your header NSString *ipAddress declares an ivar.
I the implementation self.ipAddress refers to a property.
You declared no such property. Hence the error.
After the edit your problem becomes apparent:
You do not declare a method -(void)setIpAddress:(NSString *)address;
That's what would make Xcode allow you to use property syntax (dot notation) for the setter—even though it's not an actual property.
You are declaring instance variables, not properties. Just put the #property directive in front of the lines.
#interface ProxyProfileObject : NSObject <NSCoding> {}
#property NSString *profileName;
#property NSString *ipAddress;
#property NSString *port;
Edit: Don't write explicit getters and setters. Use the (error-free) synthesized accessors provided by the #property declaration.

Will there be retain cycle?

Here is some abstract code. There is base class "BaseClass" and child class "MyClass"
BaseClass
#property (nonatomic, copy) BlockType block;
- initBaseClassWithBlock:(BlockType)block {
self = [super init];
if (self) {
self.block = block;
}
return self;
}
MYClass : BaseClass
#property (strong, nonatomic) NSString *myString;
- (instancetype)init {
self = [super initBaseClassWithBlock:^{
NSLog(#"%#", self.myString);
}
return self;
}
Will there be retain cycle in MyClass init method?
Yes; that is a retain cycle.
You can check by pasting the code into a simple project and then using Xcode 8's memory graph debugger.
Copy/paste this compilable version of your code then build and run. It'll run forever and do nothing. Click the little object graph debugger icon (the three circles with lines in them) and it'll show you that you have a strong reference from the instance of sub back to itself via the block.
#interface Base:NSObject
#property (nonatomic, copy) dispatch_block_t block;
#end
#interface Sub:Base
#property (strong, nonatomic) NSString *myString;
#end
int main(int argc, const char * argv[]) {
#autoreleasepool {
Sub *s = [[Sub alloc] init];
}
dispatch_main();
return 0;
}
#implementation Base
- initBaseClassWithBlock:(dispatch_block_t)block
{
self = [super init];
if (self) {
self.block = block;
}
return self;
}
#end
#implementation Sub
- (instancetype)init {
if (self = [super initBaseClassWithBlock:^{
NSLog(#"%#", self.myString);
}]) {
;
}
return self;
}
#end

Retrieving custom class object properties from NSMutableArray

//controller header file.
#interface MasterVaultDataViewController : UITableViewController
#property(nonatomic,strong) NSMutableArray *sectionTittle;
#end
//controller m class
#import "MasterVaultDataViewController.h"
#import "PasswordKeeper.h"
#interface MasterVaultDataViewController (){
PasswordKeeper *cathegory1,*cathegory2,*cathegory3;
UIImage *image2;
}
#end
#implementation MasterVaultDataViewController
-(NSMutableArray *) sectionTittle{
if(!_sectionTittle){
_sectionTittle = [[NSMutableArray alloc] init];
}
return _sectionTittle;
}
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
cathegory1 = [[PasswordKeeper alloc]init];
[cathegory1 setTitle:#"Concepcion"];
[cathegory1 setSubtitle:#"Parte Del Sur"];
cathegory2 = [[PasswordKeeper alloc]init];
[cathegory2 setTitle:#"Santiago"];
[cathegory2 setSubtitle:#"Norte"];
cathegory3 = [[PasswordKeeper alloc]init];
[cathegory3 setTitle:#"Bariloche"];
[cathegory3 setSubtitle:#"Argentine"];
[_sectionTittle addObject:[cathegory1 class]];
//Custom Class h file
#interface PasswordKeeper : NSObject
#property(nonatomic,strong) NSString *title;
#property(nonatomic,strong) NSString *subtitle;
#end
//custom class m file
#import "PasswordKeeper.h"
#implementation PasswordKeeper
#end
I have created 3 objects from my PasswordKeeper class and added them to a
NSMutableArray property in my controller. i have first set up the properties of each object.
Now i want to retrieve the properties of the objects. Here is some code.

'Property not found' in subclass constructor

I have the next code:
GenericClass.h:
#interface GenericClass : NSObject
#property (nonatomic) char tile_inicial;
#property (strong, nonatomic) NSString *color;
GenericClass.m
#implementation GenericClass
-(id)init
{
self = [super init];
return self;
}
- (id)initTodo:(char) tile
{
_tile_inicial = tile;
return self;
}
#end
Animals.h:
#import "GenericClass.h"
#interface Animals : GenericClass
#property (nonatomic) bool fly;
#property (strong, nonatomic) NSString *sound;
#end
#interface Cow : Animals
#property (nonatomic) bool daLeche;
#end
Animals.m
#import "Animals.h"
#implementation Animals
-(id)init
{
self = [super init];
return self;
}
- (id)initAnimal:(bool)fly :(NSString *) sound :(char) tile
{
_fly = fly;
_sound = sound;
self = [super initTodo: tile];
return self;
}
#end
#implementation Cow
-(id)init
{
self = [super initAnimal: false :#"Muu Muu": 'v'];
if (self) {
_daLeche = true;
}
return self;
}
#end
The issue is I would like to call directly from the Cow constructor to any property (for example color or sound) and initialize it.
But if I try to do it without call the parent constructor it returns: "Property not found"
Any idea?
Thanks in advance

Why can't I populate my controller with items?

I'm using an ItemController to provide a list of items to use in a tableview. I can't seem to populate the controller though, and I'm not sure why.
Here's the code for the controller class:
.h
#import <Foundation/Foundation.h>
#class Item;
#interface ItemController : NSObject
#property (nonatomic, copy) NSMutableArray *items;
- (NSUInteger)countOfList;
- (Item*)objectInListAtIndex:(NSUInteger)theIndex;
- (void)addItem:(Item *)item;
#end
.m
#import "ItemController.h"
#import "Item.h"
#interface ItemController ()
#end
#implementation ItemController
- (NSUInteger)countOfList {
return [self.items count];
}
- (Item *)objectInListAtIndex:(NSUInteger)theIndex {
return [self.items objectAtIndex:theIndex];
}
- (void)addItem:(Item *)item {
[self.items addObject:item];
}
#end
Item.m
#implementation Item
-(id)initWithName:(NSString *)name{
self = [super init];
if (self) {
_name = name;
return self;
}
return nil;
}
#end
I'm using the following code to populate the list:
ItemController* controller = [[ItemController alloc] init];
for (NSString* key in raw_data) {
NSLog(key); // This outputs the keys fine
[controller addItem:[[Item alloc] initWithName:key]];
}
NSLog([NSString stringWithFormat:#"%d",[controller countOfList]]); // Always 0
You need to initialize the array in the init methond.
- (id)init {
self = [super init];
if (self) {
self.items = [[NSMutableArray alloc] init];
}
return self;
}
You need to initialize your variable items. In your init method, call self.items = [NSMutableArray new]; and also change your array property from copy to retain.
I also believe your class ItemController should be of kind UIViewController and not NSObject.
#interface ItemController : UIViewController
You don't initialise the _items instance variable anywhere, so it's always nil. The result of any integer-returning method called on nil will be 0, so you see that the count is 0.