I'm trying to figure out if there is a general way to essentially wipe or encrypt the memory associated with NSObjects. I don't really care if it's a bit cumbersome, I just want to make sure it really can't be read.
For example if I have an
NSString* str = [[NSString alloc] initWithFormat:#"TESTING"];
it's relatively simple to do
unsigned char* strPtr = (unsigned char *) CFStringGetCStringPtr
((CFStringRef) str, CFStringGetSystemEncoding());
memset(strPtr, 0, [str length]);
And I can do similar things for NSData. But I would really like to have something more general.
I have looked into, with no luck:
Zones, which seem like they are no longer used.
Creating a parent class of NSObject and casting everything to that and keeping track of the memory regions. This has just been a complete pain though.
Encrypting the actual contents of the data and forcing a decrypt on access. This gets back to the problem of knowing something about every single type.
Encrypting then decrypting memory regions, can't find a way to reliably know where in memory a general object is.
Any hints or ideas would be greatly appreciated.
You can add a category to NSObject that uses reflection via the runtime API. This can be used to clear ivars/properties, even properties declared as readonly.
One drawback is that it does not clear certain properties, such as the frame of a UIView, and I'm not sure why it misses that.
NSObject+Scrub.h:
#interface NSObject (Scrub)
- (void) scrub;
#end
NSObject+Scrub.m:
#import "NSObject+Scrub.h"
#import <objc/runtime.h>
#implementation NSObject (Scrub)
- (void) scrub
{
Class myClass = [self class];
unsigned int count;
//Scrub the Ivars
Ivar *ivars = class_copyIvarList(myClass, &count);
for (int i = 0; i < count ; i++) {
Ivar ivar = ivars[i];
object_setIvar(self, ivar, nil);
}
free(ivars);
}
#end
Good luck!
Related
Appending new string to old string is causing crash.
(abnormally works if i do as like this StructIOS.server = #""; StructIOS.server = [StructIOS.server stringByAppendingString:#".stackoverflow.com"];).
struct.h:
struct iOS {
__unsafe_unretained NSString *input_url;
__unsafe_unretained NSString *use_url;
__unsafe_unretained NSString *server;
};
struct iOS StructIOS;
ViewController.m:
StructIOS.use_url = #"relay/pincode/apicode/accesskey/1/2/3/99/../900";
NSArray *work_array = [StructIOS.use_url componentsSeparatedByString:#"/"];
StructIOS.server = [work_array objectAtIndex:0];
if([StructIOS.server length] > 0) {
NSLog(#">>> 4: %#", StructIOS.server); // OK!!
StructIOS.server = [StructIOS.server stringByAppendingString:#".stackoverflow.com"]; // FAIL!!
NSLog(#">>> 5: %#", StructIOS.server);
}
Output:
>>> 4: relay
crash
Expected output:
>>> 5: relay.stackoverflow.com
EDIT: following way worked without crash
NSString *fool_ios;
// read from NSString type
StructIOS.server = fool_ios;
// save to NSString type
fool_ios = StructIOS.server;
The answer is two-fold:
Don't store objects in Objective-C Structs. ARC won't manage the memory for them.
Don't use unsafe_unretained unless you understand exactly what it does and exactly why you need it.
Simply make your variables instance variables of your class. That will make them strong, which is what you want.
EDIT:
Note that in Swift, it is valid to store objects in a Struct. Swift is able to memory manage them inside a struct, where C does not.
Any time the compiler forces you to use __unsafe_unretained, you're likely doing something wrong. (There are exceptions to that, but at your level of understanding, you should pretend that __unsafe_unretained doesn't exist.)
Why are they __unsafe_unretailed?
componentsSeparatedByString() will presumably internally be creating some substrings which you are not taking ownership of due to using __unsafe_unretained, thus they are being deleted when componentsSeparatedByString function got out of scope.
The log at line 4 is working purely though chance and good luck as the string is deallocated but still there at that memory location.
If you rewrite the struct as a simple class (which inherits from NSObject) it should work.
I have a core data entity that has a structure like this:
number (integer 16),
reference (binary)
image (binary)
I have created a class for that entity.
The header of that class has these declarations for the entity property.
#property (nonatomic, retain) NSNumber * number;
#property (nonatomic, retain) NSData * reference;
#property (nonatomic, retain) NSData * image;
but in fact, these 3 properties are
number = NSInteger
reference = NSArray
image = UIImage
because I cannot store arrays and images on core data directly, I have to convert it to NSData to save but I don't care for the property being declared as NSData, because the conversion to and from NSData is something internal to the entity and should not be exposed to code outside the class.
I want these header properties to be declared like
#property (nonatomic, assign) NSInteger number;
#property (nonatomic, retain) NSArray * reference;
#property (nonatomic, retain) UIImage * image;
and I want to, for example, when I assign an array to reference that is converted to NSData internally.
I know I have to create setters and getters to do that but my problem is that the entity is already using these names. Obviously I can rename all core data entities to have a prefix like xnumber, xreference, ximage, etc., so I will have no collisions between the names/types I want to expose and those I want to hide internally.
Is there any other alternative to that? My fear is ending with a sea of references that are similarly.
What you did in your application is probably most common fail using core data. By no means you should be encouraged to use the core data classes directly as you did, do always use subclassing, categories or (best of all) use wrappers.
Since in most cases when you edit an entity in your model you wish to delete the auto generated file(s) and create new ones those files should be unmodified. This is the main reason I discourage you to use any quick fixes such as modifying the names in your model and then creating the custom setters.
Why I suggest the wrappers most is because you can build your own interface with it. You can create exactly as many methods, accessories as you need on it, you can use data protection such as having read-only parameters... So when you modify the data model there should be no difference in the application at all, when you will possibly add some extra tables for some optimisations or some internal functionality you will have no issues hiding those accessories. Other then that having an extra layer will make it very easy for you to create some caching, easy debugging since you can put a breakpoint or log to more or less any and every accessory, you can internally maintain multithreading operations...
I can understand at this point migrating your code to some other system might take a bit long but that is something you should consider. If the application is anything but almost done I suggest you do migrate it: If you create a wrapper with same properties as are already used in the application it is possible to simply change the class names where it was already used, this shouldn't take too long. If you choose to continue working as it is you will most likely encounter some much harder issues and if nothing else remember this when you will start a new application.
Edit: Wrapper explanation and example
By wrapper I mean a class instance that holds another instance and builds an interface around it. Let me show you a nice example first:
Interface:
#interface EntityWrapper : NSObject
#property NSInteger number;
#property UIImage *image;
+ (NSArray *)fetchAll;
+ (void)invalidateCache;
#end
Implementation:
#class EntityName;
static NSArray *__entityCache = nil;
#interface EntityWrapper() {
EntityName *_boundEntity;
}
#end
#implementation EntityWrapper
- (instancetype)initWithEntity:(EntityName *)entity {
if((self = [super init])) {
_boundEntity = entity;
}
return self;
}
+ (NSArray *)fetchAll {
if(__entityCache == nil) {
NSMutableArray *toReturn = [[NSMutableArray alloc] init];
NSArray *entityArray = nil; //fetch from data base
for(EntityName *entity in entityArray)
[toReturn addObject:[[EntityWrapper alloc] initWithEntity:entity]];
__entityCache = [toReturn copy];
}
return __entityCache;
}
+ (void)invalidateCache {
__entityCache = nil;
}
- (void)setNumber:(NSInteger)number {
_boundEntity.number = #(number);
}
- (NSInteger)number {
return [_boundEntity.number integerValue];
}
- (void)setImage:(UIImage *)image {
_boundEntity.image = UIImagePNGRepresentation(image);
}
- (UIImage *)image {
return [[UIImage alloc] initWithData:_boundEntity.image];
}
#end
As you can see here I am building an interface around the entity using custom setters and getters. I even create a method to fetch all objects from the data base, next step might be to fetch them with some predicate or in this case rather some custom options. I also added a most simple cache just to see the concept.
The number is now a NSInteger instead of a NSNumber which can be quite a convenience but be careful doing this as you might need to know if number is nil. For this case you could also create another property such as BOOL numberIsSet.
Pretty much the same goes for the image. You need no transformers at all, just a getter and a setter (which is pretty much the same with transformers but this approach is much more dynamic).
So creating the wrapper kind of gives you the ultimate power. The idea is to create as small interface as possible and as simple as possible. That means there are just as many methods in the header file as needed, rest is hidden. The logic behind these methods can be extremely complicated but will still be maintainable since it is a closed system (does not depend on nothing but the entity), to give you an example:
Interface:
#property (readonly) NSDecimalNumber *heavyValue;
Implementation:
- (NSDecimalNumber *)heavyValue {
NSDecimalNumber *valueA = _boundEntity.valueA;
NSDecimalNumber *valueB = _boundEntity.valueB;
NSDecimalNumber *valueC = _boundEntity.valueC;
return [[valueA decimalNumberByAdding:valueB] decimalNumberByDividingBy:valueC];
}
Now this is quite a standard procedure and will work great but this method can be quite heavy on the CPU. If this method is called a lot you might get to a point where you want to optimise by storing the result into the entity itself. So all you do is add another value into the model heavyValue and the code:
- (NSDecimalNumber *)heavyValue {
NSDecimalNumber *toReturn = _boundEntity.heavyValue;
if(toReturn == nil) {
NSDecimalNumber *valueA = _boundEntity.valueA;
NSDecimalNumber *valueB = _boundEntity.valueB;
NSDecimalNumber *valueC = _boundEntity.valueC;
toReturn = [[valueA decimalNumberByAdding:valueB] decimalNumberByDividingBy:valueC];
_boundEntity.heavyValue = toReturn;
}
return toReturn;
}
- (void)setValueA:(NSDecimalNumber *)valueA {
_boundEntity.valueA = valueA;
_boundEntity.heavyValue = nil; //this invalidates the value
}
So that is quite an extreme change in logic behind a simple getter but the rest of your code is unharmed, it still all works as it should.
Sorry if this should be obvious but I'm not finding the answer.
This is part of some code I am using and I save the reference to tempData and the length. I need to know how to use that reference and the length to later retrieve the CGPoints. Is this possible? Thanks for any help!
- (void)setData:(float *)theData length:(int)length {
CGPoint *tempData = (CGPoint *)calloc(sizeof(CGPoint), length);
for(int i = 1; i < length - 1; i++) {
tempData[i] = CGPointMake(i, theSampleData[i]);
}
}
Ok, so you're dynamically allocating memory and using it to store values. Sure, you can do that.
Instead of making your setData method create a local variable tempData, make tempData an instance variable of your class. Set it to nil in your init method. Also make your length variable an instance variable and initialize it to zero.
In your setData method, allocate the pointer and save your data to it. Also save the length.
Then, anywhere else in your class, you can simply index into your tempData variable, just like you are doing to set the values.
Write a dealloc method for the class that checks to see if tempData is nil. If it's not, free it.
This is basic C memory management using malloc'ed memory (or calloc'ed memory - same thing) and pointers.
You allocate the space, but the pointer to the new storage is local in scope and will be lost.
You want to use a property (or instance variable) to store the value.
the preferred method is to use a class extension inside your .m file to keep that information private:
#interface MyClass ()
#property (nonatomic, assign) CGPoint *points;
#property (nonatomic, assign) NSUInteger pointCount;
#end
You should also implement
- (void)dealloc {
[super dealloc];
free(points);
points = NULL;
}
In my child view controller, I have a property defined as:
#property (nonatomic, copy) NSString *name;
In view controller A, the Parent, I have the following:
NSString *temp = currency.name; //This is because currency is a Core Data Managed Object.
//I wanted to make sure it wasn't a confounding factor.
childViewController.name = temp;
if(childViewController.name == temp)
NSLog(#"I am surprised");
The problem is that if statement finds equivalency and the "I am surprised" is printed. I thought that == should be checking if they're the same object, and that the use of copy in the property declaration should ensure the setter is making a copy. I checked in the debugger and they are both pointing to the same string. (Which I believe is immutable, which may be why this is happening?)
The same thing happens even if I write childViewController.name = [temp copy];, which I find shocking!
Can anyone explain what is going on here?
Edit: I removed a bit here on worrying about a circular reference which I realized wasn't a concern.
This is an optimization.
For immutable objects, it's superfluous to create an actual copy, so - copy is often implemented as a simple retain, i. e.
- (id)copy
{
[self retain];
return self;
}
Try assigning a mutable object (e. g. NSMutableString) to the property, and you will get the "expected" behavior.
I am still new to objective-c and I need some insight about variable declaration.
The point of my program is to read a message delivered in several NSData parts. Whenever the program receive a NSData it adds it to the already partially complete message as unsigned chars. This means that the message buffer must be define as a property of the viewController:
#property unsigned char* receiveBuf;
#property int bufSize;
At that point the program has a NSData object named data, and treat it like this:
int len = [data length];
unsigned char* tempBytebuf = (unsigned char*)[data bytes];
for(int i = 0; i < len; i++){ //read all bytes
if (tempBytebuf[i] == 0x7E) { //this char means start of package
_bufSize = 0;
}
else if (tempBytebuf[i] == 0x7D) { //this char means end of package
[self readMsgByte:_receiveBuf :_bufSize];
}
else { //any other char is to be put in the message
_receiveBuf[_bufSize++] = tempBytebuf[i]; //Error happens here
}
}
if I proceed like this it will result in an error EXC_BAD_ACCESS.
If I could tell the program to reserve space for the buffer it would solve the problem:
#property unsigned char receiveBuf[256];
but it seems I can't do this with #properties.
Is there a way of assigning that space in the ViewDidLoad() for example or somewhere else?
Thanks for your support!
EDIT 1:
It seems I just found a solution in some of my previous codes, I should have declare my char table in the implementation instead.
#implementation ViewController
{
unsigned char msgBuf[256];
}
Still if someone could tell me the real difference between the #property and implementation space for variable declaration that would prevent me from doing other mistakes like this.
Thanks a lot.
If you needed to declare that as unsigned char*, then malloc/calloc/realloc/free are your friends.
In reality, making that ivar NSMutableData and using APIs like -appendBytes:length: should be all that's necessary.
Use NSMutableData:
#property (strong) NSMutableData *recievedData;
It provides a nice wrapper around an arbitrary piece of memory who's contents and length can change at any time - and most importantly it fits in perfectly with the objective-c runtime and memory management.
Just create an empty (0 length) data object like this:
self.receivedData = [[NSMutableData alloc] init];
And then at any time you can do:
[self.recivedData appendBytes:bytes length:length];
Or:
[self.recievedBytes appendData:anotherNSDataObj];
From there you can read it with the getBytes: method.
There are other ways to do it, by declaring lower level instance variables, but #property is the modern approach. The older style of instance variable is able to what you tried, but we are moving away from them and it will probably be deprecated soon.