I don't have knowledge on objective c.I am using a swift file in objective-c for coredata operation.In my coredata i have to entity "Product" and "Images". Product has to-many relationship to "Images" and to-one relationship from "Images" to "Product"
#objc class DatabaseOperations: NSObject {
#objc func checkDataAvailibility()-> [Images]{
var imageList = [Images]()
let request: NSFetchRequest<Images> = Images.fetchRequest()
let sortByName = NSSortDescriptor(key: "isUploading", ascending: true)
let sortDescriptors = [sortByName]
request.sortDescriptors = sortDescriptors
let moc = CoredataStack.shared.persistentContainer.viewContext
do {
let imageCount = try moc.count(for: request)
if imageCount > 0{
imageList = try moc.fetch(request)
}
}catch {
fatalError("Error in counting home record")
}
return imageList
}
}
I am trying to access it in another view controlle
#property (nonatomic,strong) NSArray<Images *> *uploadingImage;
#property (nonatomic, assign) BOOL imageUploadingStatus;
DatabaseOperations *op = [[DatabaseOperations alloc] init];
_uploadingImage = [op checkDataAvailibility];
[_selectedImages addObject: _uploadingImage.name];
I am getting error like:-
Property 'name' not found on object of type 'NSArray *'.
Please help me to get rid of this error ?
Related
I've been getting up to speed on Dynamic Class creation at runtime in Objective-C and have hit an issue I can't quite seem to work around. After a good deal of searching around, I'm still puzzled.
The issue here is making a:
[runtimeClassInstance setValue:age forKey:#"age"];
call to an object instantiated from:
id runtimeClassInstance = [[NSClassFromString(#"Employee") alloc] init];
Which was created by
[NewClassMaker buildClassFromDictionary:#[#"FirstName", #"LastName",\
#"Age", #"Salary"]
withName:#"Employee"];
This is croaking with an NSUnknownKeyException:this class is not key value coding-compliant for the key age error.
If I use the following invocation approach, things work just fine:
SEL setAgeSelector = NSSelectorFromString(#"setAge");
NSInvocation *call = [NSInvocation invocationWithMethodSignature:[[NSClassFromString(#"Employee") class] instanceMethodSignatureForSelector:setAgeSelector]];
call.target = runtimeClassInstance;
call.selector = setAgeSelector;
NSNumber *age = #(25);
[call setArgument:&age atIndex:2];
[call invoke];
Now that static method to create the class is as such:
+(NSDictionary*)buildClassFromDictionary:(NSArray*)propNames withName:(NSString*)className
{
NSMutableDictionary* keys = [[NSMutableDictionary alloc]init];
Class newClass = NSClassFromString(className);
if(newClass == nil)
{
newClass = objc_allocateClassPair([NSObject class], [className UTF8String], 0);
// For each property name, add a new iVar, getter, and setter method for it.
for(NSString* key in propNames)
{
NSString* propName = [self propName: key];
NSString* iVarName = [self ivarName:propName];
class_addIvar(newClass, [iVarName UTF8String] , sizeof(NSObject*), log2(sizeof(NSObject*)), #encode(NSObject));
objc_property_attribute_t a1 = { "T", "#\"NSObject\"" };
objc_property_attribute_t a2 = { "&", "" };
objc_property_attribute_t a3 = { "N", "" };
objc_property_attribute_t a4 = { "V", [iVarName UTF8String] };
objc_property_attribute_t attrs[] = { a1, a2, a3, a4};
class_addProperty(newClass, [propName UTF8String], attrs, 4);
class_addMethod(newClass, NSSelectorFromString(propName), (IMP)getter, "##:");
class_addMethod(newClass, NSSelectorFromString([self setterName:propName]), (IMP)setter, "v#:#");
[keys setValue:key forKey:propName];
}
Class metaClass = object_getClass(newClass);
// This method is returning NO on purpose to find out why there is no key.
class_addMethod(metaClass, #selector(accessInstanceVariablesDirectly), (IMP)accessInstanceVariablesDirectly, "B#:");
// Auxilliary methods added to the new class instance so the accessor dynamic methods above can work.
// Not sure if the initial impl of this class maker class worked.
class_addMethod(newClass, #selector(ivarName:), (IMP)ivarNameForString, "##:#");
class_addMethod(newClass, #selector(propName:), (IMP)propNameForString, "##:#");
class_addMethod(newClass, #selector(propNameFromSetterName:), (IMP)propNameFromSetterNameString, "##:#");
// Add a customized description dynamic method to this class. It will dump out any list of properties added
// to the object during init here.
Method description = class_getInstanceMethod([NSObject class],
#selector(description));
const char *types = method_getTypeEncoding(description);
// now add
class_addMethod(newClass, #selector(description), (IMP)Description, types);
objc_registerClassPair(newClass);
}
return keys;
}
There are three possibilities here that I am stewing over:
I have missed some crucial step here to get these properties and
their dynamic accessors working in a key-value compliant fashion
If I do allow direct iVar access, is the retain for the value not
happening?
Is the NSInvocation approach the best way?
The setter method is named setAge. setValue:forKey: searches for setAge: with a colon. Add a colon at the end of the name of the setter method. In Objective-C the colons are part of the method names.
What would be "if let" equivalent in Objective C? The example snippet I want to convert to Objective C is below;
if let pfobjects = images as? [PFObject] {
if pfobjects.count > 0 {
var imageView: PFImageView = PFImageView()
imageView.file = pfobjects[0] as! PFFile
imageView.loadInBackground()
}
}
There's no direct equivalent to if let in Objective-C, because if let does Swift-specific things (unwrapping optionals and rebinding identifiers) that don't have direct equivalents in Objective-C.
Here's a nearly equivalent of your Swift code:
if (images != nil) {
NSArray<PFObject *> *pfobjects = (id)images;
if (pfobjects.count > 0) {
PFImageView *imageView = [[PFImageView alloc] init];
assert([pfobjects[0] isKindOfClass:[PFFile class]]);
imageView.file = (PFFile *)pfobjects[0];
[imageView loadInBackground];
}
}
But this Objective-C code won't verify that images only contains instances of PFObject, and should successfully create an image view as long as pfobjects[0] is a PFFile. Your Swift code will do nothing (create no image view) if images contains any non-PFObject elements.
You can use NSPredicate to verify the array contains only instances of PFObject:
NSPredicate *p = [NSPredicate predicateWithFormat:#"self isKindOfClass: %#", [PFObject class]];
NSInteger numberThatArePFObjects = [images filteredArrayUsingPredicate:p].count;
if(numberThatArePFObjects && numberThatArePFObjects == images.count){
// certain that images only contains instances of PFObject.
}
If however you weren't working with an array but a single object then it is simpler:
if([image isKindOfClass:[PFObject class]]){
// certain that image is a valid PFObject.
}
Or if you wanted a new variable:
PFObject* obj = nil;
if([image isKindOfClass:[PFObject class]] && (obj = image)){
// certain that obj is a valid PFObject.
}
You can use something like this:
NSArray<PFObject *> *pfobjects;
if ([images isKindOfClass: [NSArray<PFObject> class]] && (pfobjects = images)) {
// your code here
}
You want three things simultaneously. Let's split them:
variable as? OtherType is possible, but erases type, because it returns id. Implementation is as easy as a category on NSObject class, so it becomes NSArray *array = [jsonDict[#"objects"] ifKindOfClass:NSArray.class].
Implementation
#interface NSObject (OptionalDowncast)
- (id)ifKindOfClass:(__unsafe_unretained Class)clazz;
#end
#implementation NSObject (OptionalDowncast)
- (id)ifKindOfClass:(__unsafe_unretained Class)clazz {
return [self isKindOfClass:clazz] ? self : nil;
}
#end
if let is also possible in Objective-C if type is known, so it cannot be combined with previous thing. Easiest way is: for(NSArray *array = [self getItems]; array != nil; array = nil) { ... }, but if you want to use else branch, it gets a bit more complex. I have made SwiftyObjC pod for that, please take a look
Check generic template is not possible during type cast in Objective-C, thus you can cast to NSArray, but you can't cast to NSArray<PFObject>
I don't see iterations over your array: With all that being said, I think best example is (assuming images is an array already):
for(PFFile *file = [images.firstObject ifKindOfClass:PFFile.class]; file != nil; file = nil) {
imageView.file = file;
[imageView loadInBackground];
}
If you need to also iterate over it:
for(id object in images) {
for(PFFile *file = [object ifKindOfClass:PFFile.class]; file != nil; file = nil) {
//operate on file
}
}
You can use Objective-C++ in place of Objective-C. In this you can use the next define:
#define let const auto
Note: it is not the same exactly (Swift has wrapped values, ...) but it makes the work easier.
And through of this define you can use it of this way:
if (let pfobjects = images) {
if (pfobjects.count > 0 {
let imageView = [[PFImageView alloc] init];
imageView.file = pfobjects[0];
imageView loadInBackground();
}
}
To convert your Objective-C class in Objective-C++ class you only must change the extension of implementation file of .m to .mm
I'm a novice, and I seem to be getting multiple errors on this.
All I want is a for or while loop to print out all the superclasses of a certain Class.
Here is the pseudocode of what I want:
IDontKnowWhatClass *superClassName;
while (superClassName != nil)
{
superClassName = [[superClassName class] superclass];
NSLog(print the name);
}
Try this
Class superClassName = [self class];
while (superClassName != nil)
{
superClassName = [superClassName superclass];
NSLog(#"%#",NSStringFromClass(superClassName));
}
If you know a class itself like NSString then,
Class superClassName = [NSString class];
You can store the class name to a string like
NSString *className = NSStringFromClass(superClassName);
And if you want to create an object of the class from which class name is stored in a string like
id object = [[NSClassFromString(className) alloc] init];
Use NSObject method names as :
objc_property_t class_getProperty(Class cls, const char *name)
//Returns a property with a given name of a given class.
Keep on finding till you get the NSObject as it is supermost class
Use this method to check for equality :
- (BOOL)isEqual:(id)object;
or
[object isKindOfClass:[SomeClass class]]
Documentation here
This will work
You can call superclass method on your current class until it gets equal to Nil (that will happen for root class, i.e. NSObject).
Class c = [IDontKnowWhatClass class];
while (c)
{
NSLog(#"%#", NSStringFromClass(c));
c = [c superclass];
}
NSString* classString = #"IDontKnowWhatClass";
Class class = NSClassFromString(classString);
while (class != nil){
NSLog(#"%#", [class description]);
class = [class superclass];
}
Suppose that in my data model, I have Pages, which have-many Comments.
I want to connect up a relationship in the model which goes from the Comment back to the Page it belongs to, but the Page object isn't nested in the response, nor is any primary key which could identify the parent Page present in the response.
At the time that I call loadObjectsAtResourcePath, all the Comments which are loaded should belong to a fixed, known Page object. One way I could hook up the relationship would be to do:
loader.onDidLoadObjects = ^(NSArray* objs) {
for (Comment* comment in objs) comment.page = self.page;
...
}
but I'm hoping there's a better way. Note that I can't use the connectRelationship family of methods, because there's no primary key in the response which could let me hook each Comment up to a Page.
You can use the delegate method - (void)objectLoader:(RKObjectLoader *)loader willMapData:(inout id *)mappableData to inject extra parameters before the mapping step. It ensures the objects and relationships will be correctly saved by RestKit if you are using core data (note the solution you gave above does not save the relationship).
Alternatively, look at this answer where I showed how to override RKObjectLoader to retrieve the page information from the URL itself.
EDIT: Here is the category I mentioned in the comment:
.h
#import <RestKit/RestKit.h>
typedef void(^RKObjectLoaderWillMapDataBlock)(id* mappableData);
#interface RKObjectLoader (Extended)
#property (nonatomic, copy) RKObjectLoaderWillMapDataBlock onWillMapData;
#end
and the .m:
#import <objc/runtime.h>
NSString* kOnWillMapDataKey = #"onWillMapData";
#implementation RKObjectLoader (Extended)
- (RKObjectLoaderWillMapDataBlock) onWillMapData {
return objc_getAssociatedObject(self, &kOnWillMapDataKey);
}
- (void) setOnWillMapData:(RKObjectLoaderWillMapDataBlock) block {
objc_setAssociatedObject(self, &kOnWillMapDataKey, block, OBJC_ASSOCIATION_COPY);
}
- (RKObjectMappingResult*)mapResponseWithMappingProvider:(RKObjectMappingProvider*)mappingProvider toObject:(id)targetObject inContext:(RKObjectMappingProviderContext)context error:(NSError**)error {
id<RKParser> parser = [[RKParserRegistry sharedRegistry] parserForMIMEType:self.response.MIMEType];
NSAssert1(parser, #"Cannot perform object load without a parser for MIME Type '%#'", self.response.MIMEType);
// Check that there is actually content in the response body for mapping. It is possible to get back a 200 response
// with the appropriate MIME Type with no content (such as for a successful PUT or DELETE). Make sure we don't generate an error
// in these cases
id bodyAsString = [self.response bodyAsString];
RKLogTrace(#"bodyAsString: %#", bodyAsString);
if (bodyAsString == nil || [[bodyAsString stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]] length] == 0) {
RKLogDebug(#"Mapping attempted on empty response body...");
if (self.targetObject) {
return [RKObjectMappingResult mappingResultWithDictionary:[NSDictionary dictionaryWithObject:self.targetObject forKey:#""]];
}
return [RKObjectMappingResult mappingResultWithDictionary:[NSDictionary dictionary]];
}
id parsedData = [parser objectFromString:bodyAsString error:error];
if (parsedData == nil && error) {
return nil;
}
// Allow the delegate to manipulate the data
if ([self.delegate respondsToSelector:#selector(objectLoader:willMapData:)]) {
parsedData = [parsedData mutableCopy];
[(NSObject<RKObjectLoaderDelegate>*)self.delegate objectLoader:self willMapData:&parsedData];
}
if( self.onWillMapData ) {
parsedData = [parsedData mutableCopy];
self.onWillMapData(&parsedData);
}
RKObjectMapper* mapper = [RKObjectMapper mapperWithObject:parsedData mappingProvider:mappingProvider];
mapper.targetObject = targetObject;
mapper.delegate = (id<RKObjectMapperDelegate>)self;
mapper.context = context;
RKObjectMappingResult* result = [mapper performMapping];
// Log any mapping errors
if (mapper.errorCount > 0) {
RKLogError(#"Encountered errors during mapping: %#", [[mapper.errors valueForKey:#"localizedDescription"] componentsJoinedByString:#", "]);
}
// The object mapper will return a nil result if mapping failed
if (nil == result) {
// TODO: Construct a composite error that wraps up all the other errors. Should probably make it performMapping:&error when we have this?
if (error) *error = [mapper.errors lastObject];
return nil;
}
return result;
}
#end
Seems simple enough - I'm creating one master NSMutableDic and filling it with more of them.
What's an easy way to access the contents of a dictionary like this?
Although this isn't Python, perhaps something to the extent of 'taskDict[4]['assignedby']'?
Here's the code which works fine and dandy:
int counter = 0;
NSArray *cols = [GetProjectInfo getTaskColumns];
NSArray *rows = [GetProjectInfo fetchAll:projectName];
NSMutableDictionary *taskDict = [NSMutableDictionary dictionary];
NSMutableDictionary *localDict = [NSMutableDictionary dictionary];
for (int x=0; x < rows.count; x++) {
NSString *rowData = [rows objectAtIndex:x];
NSString *colData = [cols objectAtIndex:counter];
//Assign the values colData(key) and rowData(value) into localDict.
[localDict setValue:rowData forKey:colData];
counter ++;
if (counter >= cols.count) {
counter = 0;
//Add the whole localDict to the global dictionary (taskDict)
[taskDict setObject:localDict forKey:localDict];
//Reset the localDict so that we can populate it with the next set
[localDict removeAllObjects];
}
}
NSLog(#"%#",taskDict);
returns something to the extent of:
{
person = "Ryan";
assignedby = jfreund;
complete = False;
timeassigned = "15:35:00";
} = {
};
{
person = "Tim";
assignedby = klang;
complete = True;
timeassigned = "16:59:07";
} = {
};
Anybody care to throw some ideas this direction?
This doesn't directly answer your question; but rather than store your object graph as nested dictionaries, could you instead use NSObject subclasses to encapsulate your data so that you don't have to traverse hierarchies of dictionaries? For example, (mind you, I know nothing about your application's model layer...) could you break the conceptual model into Project and Task objects, e.g.
#interface Task : NSObject <NSCoding>
{
NSString *_name;
NSString *_owner;
NSString *_assignedBy;
BOOL _complete;
NSDate *_timeAssigned;
// etc.
}
And then Projects are, in turn, composed of Tasks:
#interface Project : NSObject <NSCoding>
{
NSString *_name;
NSString *_dateStarted;
NSMutableArray *_tasks;
// etc.
}
It's a more object-oriented way of structuring the application's model layer. There's nothing about this mechanism that would preclude you from serializing the data to a plist so long as your classes conform to the NSCoding protocol.