How to access the object - objective-c

I would like to access the the _news items in a loop. But don't know how to get this done.
My Game.m looks like
#import "Game.h"
#implementation Game
#synthesize homename = _homename;
#synthesize guestname = _guestname;
#synthesize date = _date;
#synthesize gametype = _gametype;
#synthesize news = _news;
#synthesize gameId = _gameId;
-(NSString*)description{
return [NSString stringWithFormat:#"%# gegen %# (%#)", self.homename, self.guestname, self.gametype];
}
#end
My Game.h looks like
#import <Foundation/Foundation.h>
#import <RestKit/RestKit.h>
#import "News.h"
#interface Game : NSObject {
NSString* _homename;
NSString* _guestname;
NSString* _date;
NSString* _gametype;
NSNumber* _gameId;
// News* news;
#public
NSArray* _news;
}
#property (nonatomic, retain) NSString* homename;
#property (nonatomic, retain) NSString* guestname;
#property (nonatomic, retain) NSString* date;
#property (nonatomic, retain) NSString* gametype;
//#property (nonatomic, retain) News* news;
#property (nonatomic, retain) NSArray* news;
#property (nonatomic, retain) NSNumber* gameId;
#end
My News.h looks like
#import <Foundation/Foundation.h>
#import <RestKit/RestKit.h>
#interface News : NSObject {
NSString* _minute;
NSString* _title;
NSString* _bodytext;
NSString* _player;
}
#property (nonatomic, retain) NSString* minute;
#property (nonatomic, retain) NSString* title;
#property (nonatomic, retain) NSString* bodytext;
#property (nonatomic, retain) NSString* player;
#end
My news.m looks like
#import "News.h"
#implementation News
#synthesize player = _player;
#synthesize title = _title;
#synthesize bodytext = _bodytext;
#synthesize minute = _minute;
#end
And the code where I want to access the variable looks like:
- (void)objectLoader:(RKObjectLoader*)objectLoader didLoadObjects:(NSArray*)objects {
NSLog(#"Loaded statuses: %#", objects);
HeaderText.text = [NSString stringWithFormat:#"%#", objects ];
// for(News* n in _news) NSLog([n _bodytext]);
// for (id object in objects) {
// NSLog(#"News = %#", object );
// }
}
The NSLog with objects looks good for the game. The next thing is that I want to do something like (above is more pseudo code than real code because I don't know how to do it right):
- (void)objectLoader:(RKObjectLoader*)objectLoader didLoadObjects:(NSArray*)objects {
NSLog(#"Loaded statuses: %#", objects);
HeaderText.text = [NSString stringWithFormat:#"%#", objects ];
// loop all
for (id object in objects) {
news = objects.news;
for (id mynews in news) {
NSLog(#"News minute = %#", news.minute );
NSLog(#"News title = %#", news.title );
NSLog(#"News bodytext = %#", news.bodytext );
NSLog(#"News player = %#", news.player );
}
}
}
How to do the getter/setter methods right (so that I can use it here)?
Sorry for the surely stupid question but I don't get the point with it.

Two things:
1stly, is the _news object a private variable, without having a property declaration (getters and setters for e.g.)? The '_variableName' format is usually used to denote private variables.
2ndly, if it is not a private variable, do all the items within the _news array belong to the same class?
If so, you can do a
for (NewsObject *theNewsObject in _news)
{
//code here
}
The for(id randomObject in array) is useful when you don't know what type of object is in the array or if the objects contained in the array are of different types.
Now, again, all the objects inside the NewsObject ought to be public properties that can be accessed by other classes (they should have getters and setters).
Hope this helps. :)
EDIT FOR UPDATED QUESTION
So, if I'm getting your question correctly, you have a Game object, which has an array of News object inside it.
So, in your Game.h
NSString* _homename;
NSString* _guestname;
NSString* _date;
NSString* _gametype;
NSNumber* _gameId;
NSArray * _newsObjects; //declare it as NSMutableArray if you need to mutate it
Now, where you declare your properties;
#property(nonatomic, retain)NSArray *newsObjects
Synthesize it like you normally would in the Game.m file
You are creating the getters/setters automatically by using the #synthesize directive. It creates the getters and setters for you.
Again, from your code, it looks like the NSArray of objects that are passed through the method
- (void)objectLoader:(RKObjectLoader*)objectLoader didLoadObjects:(NSArray*)objects
consist of Game objects.
So, to access the News object from within the array of Game objects, import News.h and Game.h in the class where this method is being executed, and do the following:
- (void)objectLoader:(RKObjectLoader*)objectLoader didLoadObjects:(NSArray*)objects {
NSLog(#"Loaded statuses: %#", objects);
// loop all
for (Game *gameObject in objects) {
NSArray *newsObjectArray = [gameObject newsObjects] //or gameObject.newsObject
for (News *mynews in newsObjectArray) {
NSLog(#"News minute = %#", mynews.minute );
NSLog(#"News title = %#", mynews.title );
NSLog(#"News bodytext = %#", mynews.bodytext );
NSLog(#"News player = %#", mynews.player );
}
}
}
What I found in your code that there was code that was being executed which was not declared in any part of the example that you posted.
What the code above will do is it will look through the Game object array (called objects).
Then, for each gameObject within that array, it will loop through the array of newsObject for that gameObject.
Hope this helps. :)

Related

Swift: "Mapper is not a type", using custom mapping class for arrays in swift and Objective C

I have an 2 objective C classes:
Class 1 scanDatabase (Scans a database and puts that into a mutable array)
Class 2 Mapper (Is a mapping class for the database scan "model")
In objective C this successfully scans the database and puts it into a mutable array. Using the mapping class I can access individual groups of elements (AlbumTitles) like so:
for (Mapper *mapper in scanResult) {
NSLog(#"%#", mapper.AlbumTitle);
}
Everything is working as it should and I can return individual elements from my array i.e as above I am only returning album titles.
I then need to use that array in Swift. I call the objective C in my Swift class and again it runs fine and creates the array. This is done with:
let scanTable = ScanTable();
let scanMapper = Mapper();
scanTable.scanTableDo();
but when I try to retrieve a particular set of items like Album title as I did in the objective C for loop above I get the error "scanMapper is not a type" (scanMapper is my swift instance of the objective C mapper class:
I tried two different ways and both have the same error:
for mapper: scanMapper in scanTable.scanResult {
print("\(mapper.AlbumTitle)")
}
for object in scanTable.scanResult as! [scanMapper] {
print("\(mapper.AlbumTitle)")
}
Can I use an objective C class as a model/mapper and not sure whether I would need to recreate it in Swift.
I will include the mapper and scanTable .h and .m code just in case it is needed, plus the bridging header:
Mapper.h:
#import <Foundation/Foundation.h>
#import <AWSDynamoDB/AWSDynamoDB.h>
#interface Mapper : AWSDynamoDBObjectModel <AWSDynamoDBModeling>
#property (nonatomic, strong) NSNumber *SongID;
#property (nonatomic, strong) NSString *Artist;
#property (nonatomic, strong) NSString *SongURL;
#property (nonatomic, strong) NSString *Location;
#property (nonatomic, strong) NSNumber *UserRatings;
#property (nonatomic, strong) NSNumber *AVGUserRating;
#property (nonatomic, strong) NSString *Category;
#property (nonatomic, strong) NSString *PictureURL;
#property (nonatomic, strong) NSNumber *SongDuration;
#property (nonatomic, strong) NSString *SongTitle;
#property (nonatomic, strong) NSNumber *AVGMusicianRating;
#property (nonatomic, strong) NSString *AlbumTitle;
#end
Mapper.m
#import <AWSDynamoDB/AWSDynamoDB.h>
#import "Mapper.h"
#implementation Mapper
+ (NSString *)dynamoDBTableName {
return #"Songs";
}
+ (NSString *)hashKeyAttribute {
return #"SongID";
}
#end
ScanTable.h:
#import <Foundation/Foundation.h>
#import <AWSDynamoDB/AWSDynamoDB.h>
#interface ScanTable : NSObject
- (void) scanTableDo;
#property (nonatomic, strong) NSMutableArray *scanResult;
#end
ScanTable.m
#import "ScanTable.h"
#import "Mapper.h"
#implementation ScanTable
- (void) scanTableDo {
AWSDynamoDBObjectMapper *dynamoDBObjectMapper = [AWSDynamoDBObjectMapper defaultDynamoDBObjectMapper];
AWSDynamoDBScanExpression *scanExpression = [AWSDynamoDBScanExpression new];
scanExpression.limit = #10;
[[dynamoDBObjectMapper scan:[Mapper class]
expression:scanExpression]
continueWithBlock:^id(AWSTask *task) {
if (task.error) {
NSLog(#"The request failed. Error: [%#]", task.error);
}
if (task.exception) {
NSLog(#"The request failed. Exception: [%#]", task.exception);
}
if (task.result) {
AWSDynamoDBPaginatedOutput *paginatedOutput = task.result;
NSMutableArray *scanResult = [[NSMutableArray alloc] initWithArray:paginatedOutput.items]; //// ADDED /////
for (Mapper *mapper in scanResult) {
NSLog(#"%#", mapper.AlbumTitle);
}
}
return nil;
}];
}
#end
//EDITED ADDED BRIDGING HEADER//
MySampleApp-Bridging-Header.h:
//
// MySampleApp-Bridging-Header.h
// MySampleApp
#import "ScanTable.h"
#import "Mapper.h"
#import "Hello World.h"
Thanks for your help
The problem is just as the error explains, you're attempting to cast the items in your array to scanMapper, which is a variable holding an instance of Mapper, not the Mapper type itself. Assuming that scanTable.scanResult is an NSArray of Mappers, try this instead:
guard let scanResult = scanTable.scanResult as? [Mapper] else {
print("scanResult was not an array of mappers!")
return
}
for mapper: Mapper in scanResult {
print("\(mapper.AlbumTitle)")
}

Unrecognized selector sent to instance

Actually, the problem is in
#property (nonatomic, copy) NSMutableArray* arrayOfObjects;
should be:
#property (nonatomic, strong) NSMutableArray* arrayOfObjects;
yeah? Thank,s for that guys!
I do not exactly understand how this bug worked, but I will try to get to know :)
I have trying to solve one problem since over an hour... I am afraid it is something very simple, but something I do not understand yet. I am guessing that this is something with memory management stuff cause this is my definitely weak point yet.
Post a little bit similar to
'Unrecognized selector sent to instance'
and some others but they didnt solved my problem...
In a nutshell (pasting much cause don't know where the potential bug is):
#interface MyCustomObject : NSObject {
NSString* name;
int birthDate;
double heightInMeters;
}
#property(strong, nonatomic) NSString * name;
#property(nonatomic) int birthDay;
#property(nonatomic) double heightInMeters;
-(id)initWithDate:(int)birthDate
AndName:(NSString *)nameString
AndHeight:(double)h;
#end
//////////////////////////////////
#import "MyCustomObject.h"
#implementation MyCustomObject
#synthesize name;
#synthesize birthDay;
#synthesize heightInMeters;
-(id)initWithDate:(int)bd AndName:(NSString *)nameString AndHeight:(double)h{
if(self = [super init]){
self.birthDay = bd;
self.name = nameString;
self.heightInMeters = h;
return self;
}
return nil;
}
#end
And some kind of database for MyCustomObjects:
DataCollection.h:
#interface DataCollection : NSObject{
NSMutableArray* arrayOfObjects;
}
#property (nonatomic, copy) NSMutableArray* arrayOfObjects;
-(void)addElement:(id)el;
#end
And implementation:
#import "DataCollection.h"
#implementation DataCollection
#synthesize arrayOfObjects;
-(id)init{
if(self = [super init]){
self.arrayOfObjects = [[NSMutableArray array] init];
NSLog(#"Number of record before init: %d", [self.arrayOfObjects count]);
[self addElement:[[MyCustomObject alloc] initWithDate:1988 AndName:#"Georg" AndHeight:1.88]];
[self addElement:[[MyCustomObject alloc] initWithDate:1951 AndName:#"Sebastian" AndHeight:1.58]];
NSLog(#"Number of record before init: %d", [self.arrayOfObjects count]);
return self;
}
return nil;
}
-(void)addElement:(id)el{
// UNRECOGNIZED SELECTOR ????
[self.arrayOfObjects addObject:el];
}
#end
Result is:
2013-03-05 15:42:56.826 XMLTest[11787:207] Number of record before
init: 0 Current language: auto; currently objective-c 2013-03-05
15:43:51.446 XMLTest[11787:207] -[__NSArrayI addObject:]: unrecognized
selector sent to instance 0x6816110
Do you see what I am doing wrong? I am guessing that this is something with memory management stuff
If you change
#property (nonatomic, copy) NSMutableArray* arrayOfObjects;
to
#property (nonatomic, strong) NSMutableArray* arrayOfObjects;
That should fix your problem
I didn't actually read your question - it's too long, but I think I may know your problem. Looking only at the debugger output at the end of your post, it looks like you're trying to send addObject: to an NSArray object. If you want to add and remove objects to an array, you need to use NSMutableArray instead.

RestKit object mapping fails depending on property name

I'm seeing some strange behavior with RestKit and mapping an object. In my destination object, if I have an NSString * property named 'description', then the entire mapping fails. Changing this to any other name, or commenting it out, everything succeeds. This happens regardless if I have a map set up for the property, and I can reproduce it in simple test classes.
The JSON the server is returning:
{
id = 1;
name = item1;
},
{
id = 2;
name = item2;
}
The object I want to map to, SimpleObject.h. Note that neither the description, nor the nonexistant property is in the JSON, meaning I don't think it's because 'description' is missing:
#import <Foundation/Foundation.h>
#interface SimpleObject : NSObject
#property (nonatomic, assign) NSInteger identifier;
#property (nonatomic, retain) NSString *name;
#property (nonatomic, retain) NSString *description;
#property (nonatomic, retain) NSString *nonexistant;
#end
SimpleObject.m:
#import "SimpleObject.h"
#implementation SimpleObject
#synthesize identifier;
#synthesize name;
#synthesize description;
#synthesize nonexistant;
#end
I create the mapping in my AppDelegate:
RKObjectManager *objectManager = [RKObjectManager managerWithBaseURLString:#"http://127.0.0.1/test"];
// Setup our object mappings
RKObjectMapping *testMapping = [RKObjectMapping mappingForClass:[SimpleObject class]];
[testMapping mapKeyPath:#"id" toAttribute:#"identifier"];
[testMapping mapKeyPath:#"name" toAttribute:#"name"];
// Register our mappings with the provider using a resource path pattern
[objectManager.mappingProvider setObjectMapping:testMapping forResourcePathPattern:#"/products"];
Inside my didLoadObjects method, I have:
- (void)objectLoader:(RKObjectLoader *)objectLoader didLoadObjects:(NSArray *)objects
{
NSLog(#"Loaded products: %#", objects);
SimpleObject *obj = [objects objectAtIndex:0];
NSLog(#"Loaded product ID %d -> Name: %# ", obj.identifier, obj.name);
}
This outputs:
Finished performing object mapping. Results: {
"" = (
(null),
(null)
);
}
If I comment out the description property (but leave in nonexistant), then everything works:
Finished performing object mapping. Results: {
"" = (
"<SimpleObject: 0x8a4d040>",
"<SimpleObject: 0x8a50130>"
);
}
Is there a reason the mapping is failing only for this property name? If I change the name to anything other than 'description', it also succeeds.
It is conflicting with description property of NSObject. Rename it to other(like desc).

objective c class property variables not populated

I have the following simple class definition:
//mycommon.h
#interface CurrentPath : NSObject
#property (nonatomic, strong) NSString* PathString;
#property (nonatomic, strong) NSMutableArray* PathArr;
- (void) addAddressToPath:(NSString*) address;
#end
//mycommon.m
#implementation CurrentPath : NSObject
#synthesize PathString;
#synthesize PathArr;
- (void) addAddressToPath:(NSString*) address{
NSLog(#"addAddressToPath...");
// Add to string
self.PathString = [self.PathString stringByAppendingString:address];
// Add to Arr
[self.PathArr addObject:address];
}
#end
In another class I do #import<mycommon.h> and declare the variable like this:
#interface myDetailViewController :
{
CurrentPath* currentPath;
}
- (void) mymethod;
#end
and in
#implementation myDetailViewController
- void mymethod{
self->currentPath = [[CurrentPath alloc] init];
NSString* stateSelected = #"simple";
[self->currentPath addAddressToPath:stateSelected];
}
#end
Problem is that the PathString and PathArr properties of self->currentPath are empty after this method call which I think should have "simple" in them. Please help!
You have to make sure that your NSString and NSMutableArray properties are initialized when your CurrentPath object is created. Otherwise, the call to stringByAppendingString will result in nil because it is sent to a nil object.
One feasible way would perhaps be
self.currentPath = [NSString string];
// or
self.currentPath = #"";
[self.currentPath addAddressToPath:#"simple"];
More elegant and robust would be to check for nil property in the addAddressToPath method.
if (!self.pathString) self.pathString = [NSString string];
if (!self.pathArr) self.pathArr = [NSMutableArray array];
Notice that am following the objective-c convention and use property names that start with lower case letters.

What does this warning mean in Xcode?

I have a resource which is fetched from a JSON API.
The JSON is parsed into a NSDictionary which, in this case is called game.
I'm creating a new instance of my Game class based on the attributes from the JSON.
Game class has a property called userRegistered which is defined as follows:
// in Game.h
#interface
#property (nonatomic, assign) BOOL userRegistered;
// elsewhere in my code I have
Game *newGame = [[Game alloc] init];
newGame.userRegistered = ([game objectForKey:#"user_registered"] > 0);
The "user_registered" key in the dictionary will always be either 1 or 0.
Xcode warns me the I have -
warning: Semantic Issue: Incompatible integer to pointer conversion passing 'int' to parameter of type 'BOOL *' (aka 'signed char *')
Can someone please explain the issue and how I might resolve it?
Update
My full game class is defined as follows:
#import <Foundation/Foundation.h>
#interface Game : NSObject
#property (nonatomic, copy) NSString *name;
#property (nonatomic, copy) NSString *photoURL;
#property (nonatomic, copy) NSString *gameURL;
#property (nonatomic, assign) BOOL *userRegistered;
#end
// Game.m
#import "Game.h"
#implementation Game
#synthesize name = _name;
#synthesize partnerName = _partnerName;
#synthesize photoURL = _photoURL;
#synthesize gameURL = _gameURL;
#synthesize userRegistered = _userRegistered;
#end
I'm getting the error in one of my ViewControllers in this method
// api_response.body has just been set to an __NSCFArray containing
// NSDictionaries by AFNetworking
NSDictionary *game;
Game *newGame;
for (game in api_response.body){
newGame = [[Game alloc] init];
NSLog(#"Creating a new game");
// set attributes for new game instance
newGame.name = [game objectForKey:#"name"];
newGame.photoURL = [game objectForKey:#"photoURL"];
// user registered is either 0 (false) or 1 (true)
newGame.userRegistered = [[game objectForKey:#"user_registered"] intValue];
// add the game instance to the appropriate array
[self addGameToGamesArray:newGame];
newGame = nil;
}
The warning shows over newGame.userRegistered = [[game objectForKey:#"user_registered"] intValue];
[game objectForKey:#"user_registered"] is likely giving you an NSNumber object. You probably mean instead to compare the integer value inside that NSNumber object.
([[game objectForKey:#"user_registered"] intValue] > 0)
UPDATE in response to your update:
Your problem is with how you're declaring your BOOL property - you have a * that you need to remove.
#property (nonatomic, assign) BOOL *userRegistered;
should be
#property (nonatomic, assign) BOOL userRegistered;
I was able to solve this issue by simply using boolValue
game.userRegistered = [[json objectForKey:#"user_registered"] boolValue];
Thanks all for the help
objectForKey function will return an objective-c instance.
([[game objectForKey:#"user_registered"] boolValue] > 0)
([game boolForKey:#"user_registered"]==YES)