I was writing some code where I have a bunch of nested NSSets through classes, something like the following:
#interface C : NSObject
#property (nonatomic) NSString *name;
#end
#interface B : NSObject
#property (nonatomic) NSMutableSet<C *> *cset;
#property (nonatomic) NSString *name;
#end
#interface A : NSObject
#property (nonatomic) NSMutableSet<B *> *bset;
#property (nonatomic) NSString *name;
#end
And at some point, I have a function that iterates over each and every element and uses its (and the parents') names:
for (B *b in a.bset)
{
for (C *c in b.cset)
{
addToDict(a.name, b.name, c.name);
}
}
And I was wondering, is it faster to pull out these calls into a local variable? So instead of the above, we end up with something like:
NSString *aname = a.name;
for (B *b in a.bset)
{
NSString *bname = b.name;
for (C *c in b.cset)
{
NSString *cname = c.name;
addToDict(aname, bname, cname);
}
}
Would the second be faster? Normally, I would think compiler optimization should recognize the temporal usage of each variable, but I wasn't sure since each one is inside a class.
Related
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)")
}
I moved my app to XCode 6 and found this problem. I have NSObject and it stopped returning objects when initialized, I use XCode 6 iPhone 6 Simulator.
My .h file:
#import <Foundation/Foundation.h>
#interface RBGAlpha : NSObject{
NSString *red;
NSString *blue;
NSString *green;
NSString *alpha;
}
#property (nonatomic, retain) NSString *red;
#property (nonatomic, retain) NSString *blue;
#property (nonatomic, retain) NSString *green;
#property (nonatomic, retain) NSString *alpha;
-(id)initWithName:(NSString *)r bl:(NSString *)b gr:(NSString *)g al:(NSString *)a;
#end
my .m file
#import "RBGAlpha.h"
#implementation RBGAlpha
#synthesize red,blue,green,alpha;
-(id)initWithName:(NSString *)r bl:(NSString *)b gr:(NSString *)g al:(NSString *)a{
self = [super init];
if (self) {
self.red = r;
self.blue = b;
self.green = g;
self.alpha = a;
}
return self;
}
#end
I use something like this in viewDidLoad method to create my objects:
RBGAlpha *tmpObj=[[RBGAlpha alloc] initWithName:#"0.01" bl:#"0.01" gr:#"0.01" al:#"1.00"];
However, while running the app in Simulator iPhone 6 this returns nothing
Has anybody dealt with that kind of problem?
I think that you're being mislead. There is indeed a value, that is what 0x786... in the value field means.
Summary saying 0 objects is confusing. I cannot understand why it would say that, but I bet if you typed po tmpObj into LLDB it would not return nil but the address showing next to "Value".
If you want to see something more interesting from the Xcode debugger consider implementing debugQuickLookObject.
On a side note, you can omit the definition of your instances variables in
#interface RBGAlpha : NSObject{
NSString *red;
NSString *blue;
NSString *green;
NSString *alpha;
}
And you also don't need to #synthesize each of them anymore, the compiler included with Xcode 5 and up does this for you.
I recently started learning Objective-C. I decided to make a class called "Student" with the properties age, name, and importantly, classes. I have put the classes in an NSArray full of NSStrings. My issue is, if I define it as an #property, it automatically creates a setter and getter method for it. I dont want that in my class. How do I define an NSArray as private data in the class, without allowing for the setter and getter?
Here's the header code:
#import <Foundation/Foundation.h>
#interface Student : NSObject
#property NSString * Name;
#property unsigned short age;
#property BOOL isFullTime;
#property NSMutableArray * Classes;
#end
[NSGreeter ThanksGuys];
You have a few popular options. Of course, you can substitute types as you wish:
A:
Place it in the header, and specify #private access.
// Student.h
#interface Student : NSObject
{
#private // << note: protected is the default when declared in this scope.
NSArray * ivar;
}
#end
B:
Place it in the #implementation block. you could specify access, but that is not usually an issue because it is not visible to any other translation.
// Student.m
#implementation Student
{
#private // << note: private is the default when declared in this scope.
NSArray * ivar;
}
#end
C:
Declare it in the class continuation:
// Student.m
#interface Student ()
{
NSArray * ivar;
}
#end
D:
Declare as a property in the class continuation:
// Student.m
#interface Student ()
#property (nonatomic, copy) NSArray * ivar;
#end
#interface Student : NSObject {
#private
NSMutableArray * Classes;
}
#property NSString * Name;
#property unsigned short age;
#property BOOL isFullTime;
#end
Use the keyword #private
#interface Student : NSObject
{
#private
NSMutableArray * Classes;
}
#property NSString * Name;
#property unsigned short age;
#property BOOL isFullTime;
#end
Currently I’m trying to get the hang of a block copy with my current project. The structure of the copy is an NSMutableArray that contains NSIntegers, NSStrings another NSMutableArray and two Objects… Those objects in turn hold NSStrings. The Array contains Objects which hold an NSInteger and Two Objects which contain strings…
I believe I am supposed to use the Block Copy method for coping objects… Code is below…
I am aware the code is not releasing properly… I tried to make the code smaller for your benefit.
Any insight you could shed would be awesome.
//Main controller Excerpt
//Insert Position Information into temporary node point... Node Points can have multiple Positions (or rather you can face multiple directions at the node. Each Node has 3-4 of these.
[newNode.positionArray insertObject:[newPosition copy] atIndex:currentPosition];
Insert the temporary node into the Node Array.
[nodeArray insertObject:[newNode copy] atIndex:count];
//Main Controller Excerpt
//
// Node.h
//
#import <Foundation/Foundation.h>
#class Sequence;
#class Position;
#interface Node : NSObject {
NSInteger Id;
NSInteger currentPosition;
NSString *title;
NSMutableArray *positionArray;
Sequence *forwardSequence;
Sequence *backSequence;
}
-(id) copyWithZone: (NSZone *) zone;
#property (nonatomic, assign) NSInteger Id;
#property (nonatomic, assign) NSInteger currentPosition;
#property (nonatomic, assign) NSString *title;
#property (nonatomic, retain) NSMutableArray *positionArray;
#property (nonatomic, retain) Sequence *forwardSequence;
#property (nonatomic, retain) Sequence *backSequence;
#end
//
// Node.m
//
#import "Sequence.h"
#import "Position.h"
#import "Node.h"
#implementation Node
#synthesize Id;
#synthesize currentPosition;
#synthesize positionArray;
#synthesize title;
#synthesize forwardSequence;
#synthesize backSequence;
-(id) copyWithZone: (NSZone *) zone {
Node *nodeCopy = [[Node allocWithZone: zone] init];
nodeCopy.Id = Id;
nodeCopy.currentPosition = currentPosition;
nodeCopy.positionArray = [positionArray copy];
nodeCopy.title = title;
nodeCopy.forwardSequence = [forwardSequence copy];
nodeCopy.backSequence = [backSequence copy];
return nodeCopy;
}
#end
//
// Position.h
//
#import <Foundation/Foundation.h>
#class Sequence;
#interface Position : NSObject <NSCopying> {
NSInteger Id;
Sequence *leftSequence;
Sequence *rightSequence;
}
#property (nonatomic, assign) NSInteger Id;
#property (nonatomic, retain) Sequence *leftSequence;
#property (nonatomic, retain) Sequence *rightSequence;
-(id) copyWithZone: (NSZone *) zone;
#end
//
// Position.m
//
#import "Sequence.h"
#import "Position.h"
#implementation Position
#synthesize Id;
#synthesize leftSequence;
#synthesize rightSequence;
-(id) copyWithZone: (NSZone *) zone {
Position *positionCopy = [[Position allocWithZone: zone] init];
positionCopy.Id = Id;
positionCopy.leftSequence = [leftSequence copy];
positionCopy.rightSequence = [rightSequence copy];
return positionCopy;
}
#end
//
// Sequence.h
//
#import <Foundation/Foundation.h>
#interface Sequence : NSObject <NSCopying> {
NSInteger numberOfFrames;
NSString *imageNameScheme;
NSString *endFrame;
}
-(id) copyWithZone: (NSZone *) zone;
#property (nonatomic, assign) NSInteger numberOfFrames;
#property (nonatomic, copy) NSString *imageNameScheme;
#property (nonatomic, copy) NSString *endFrame;
#end
//
// Sequence.m
// MCIT
//
#import "Sequence.h"
#implementation Sequence
#synthesize numberOfFrames;
#synthesize imageNameScheme;
#synthesize endFrame;
-(id) copyWithZone: (NSZone *) zone {
Sequence *sequenceCopy = [[Sequence allocWithZone: zone] init];
sequenceCopy.numberOfFrames = numberOfFrames;
sequenceCopy.imageNameScheme = imageNameScheme;
sequenceCopy.endFrame = endFrame;
return sequenceCopy;
}
#end
Works like a charm now thanks all. :D
If your intent is to make this a copyable class, then you need to declare that it conforms to the NSCopying protocol like so:
#interface Node: NSObject <NSCopying> {
Falling to declare the protocol can cause other objects to believe that the class is uncopyable even if it has a copyWithZone: method.
So I have a class with a NSInteger in it and now I want to return the NSInteger value. For some kind of reason, the code for that is not working. I have already declared the #property for the NSInteger class.
#property (readwrite, assign, nonatomic) NSInteger numberFun;
- (NSInteger)sampleMethod {
...
return sample.numberFun;
}
The compiler says "Return from pointer without a cast". I'm pretty sure that means that I'm using a C type for an objective-c method. I want to know the work around for this. (Though I don't want it to return a casted NSInteger as a NSNumber).
Thanks
The following code sample compiles fine. I suggest you present a more complete example of your problem so we can figure out what you are doing wrong.
#interface MyObject : NSObject
{ }
#property (readwrite, assign, nonatomic) NSInteger numberFun;
#end
#implementation MyObject
#synthesize numberFun;
#end
#interface MyObject2 : NSObject
{ }
#property (nonatomic, copy) MyObject* sample;
#end
#implementation MyObject2
#synthesize sample;
- (NSInteger)sampleMethod { return sample.numberFun; }
#end