Here is my array:
MyTestArray=[NSMutableArray arrayWithObjects:#"Who invented america?",#"Fredrick",#"Colob bas",#"Alfred Novel",#"Sohel",nil];
I want to print it as follows :
NSLog(#"%#",[MyTestArray objectAtIndex:0]);
What i did wrong here?I just wanted to get value at the index.But my program is crashing here.:(
Just to check. what is the variable MyTestArray declared as? It should be declared as NSMutableArray.
UPDATED:
This is a memory problem. Are you retaining your MyTestArray? arrayWithObjects: method return an autorelease object. So it might only be valid for the current loop and being released when the next loop begin.
There's several way to retain object. I always recommend using property but for you it can be as simple as doing this.
MyTestArray = [[NSMutableArray arrayWithObjects:#"Who invented america?",#"Fredrick",#"Colob bas",#"Alfred Novel",#"Sohel",nil] retain];
Shouldn't crash now.
Related
I have two entities:
Ticket
TicketResolved
Both entities have the same attributes. What would be the the most efficient way to copy a Ticket NSManagedObject to TicketResolved NSManagedObject?
I'm thinking using a Category: Ticket+Copy be the least expensive way? If so, I would have to #import both Ticket and TicketResolved in the Category file.
Here is what I came up with, can someone please advise if this is the right way of going about it. I'm using NSManagedObjectSubclass for each entity.
Method in Ticket+Copy:
-(TicketResolved *)copyObjects:(Ticket *)ticket
{
TicketResolved *ticketResolved = [NSEntityDescription insertNewObjectForEntityForName:#"TicketResolved" inManagedObjectContext:self.managedObjectContext];
ticketResolved.attribute = ticket.attribute;
// Assign rest of the ticketResolved attributes values this way
return ticketResolved;
}
Now calling the Method
#import Ticket;
#import Ticket+Copy;
#implementation
....
Ticket *ticket = [NSEntityDescription insertNewObjectForEntityForName:#"Ticket" inManagedObjectContext:self.managedObjectContext];
TicketResolved *newTicketResolved = [ticket copyObjects:ticket];
// 'newTicketResolved' now has all the keys/values that 'ticket' had.
Is this a right approach or is there a simpler way to do this?
If Ticket and TicketResolved actually have the same attributes, the most efficient option is to:
Get rid of TicketResolved
Add a boolean flag on Ticket named resolved that you can set to YES when the ticket is resolved.
Use this attribute it fetch requests to get either resolved or non-resolved tickets, whichever you need.
Then you don't actually need to copy any data, and not doing work is always more efficient than doing it.
If for some reason you really want two separate entities with the same attributes, basically you have it, you need to create a TicketResolved instance and have your code copy over every attribute value. The only major problem with your code is lines like this:
Ticket *ticket = [Ticket alloc]init];
You can't create managed objects like that, because you're not calling the designated initializer. You need to either use -[NSManagedObject initWithEntity:insertIntoManagedObjectContext:] or else use +[NSEntityDescription insertNewObjectForEntityForName:inManagedObjectContext:].
Thanks to #Tom, I did correct my error in the question.
Below is the solution that worked for me:
TicketResolved *ticketResolved = [NSEntityDescription insertNewObjectForEntityForName:#"TicketResolved" inManagedObjectContext:self.managedObjectContext];
NSArray *keys = [[[ticket entity] attributesByName] allKeys];
NSDictionary *dict= [ticket dictionaryWithValuesForKeys:keys];
[ticketResolved setValuesForKeysWithDictionary:dict];
The code above does not copy the Relationships Objects. For that I had to use the code below:
ticketResolved.relationshipObject = ticket.relationshipObject;
in the context of some tests I'm writing I've found the following issue. I make use of RestKit 0.20.2, among the other natural purposes, also to manage my coredata-related aspects.
In one of those tests, I create a CoreData entity A, containing a Date as one of its fields, by assigning it a Nil value (it's an optional field). My saving function performs the following code:
NSError* myError;
[[RKTestFactory managedObjectStore].mainQueueManagedObjectContext saveToPersistentStore:&myError];
NSLog(#"Save done on main queue with myError: %#", myError);
NSAssert1(myError == Nil, #"Coredata saving error: %#", myError);
After this save, an algorithm is run which operates on A and update that date field. This algorithm works in a private managed object context:
// Get a Local Managed Object Context
NSManagedObjectContext* myLocalMOC = [[DDRestKitManager sharedInstance].objectManager.managedObjectStore newChildManagedObjectContextWithConcurrencyType:NSPrivateQueueConcurrencyType trackChanges:YES];
(DDRestKitManager is a singleton managing about every RestKit-related aspect of my project). This algorithm first retrieves A with a FetchRequest within its private managed object context, then operates on it and finally updates its date field. It then saves every CoreData related aspect it dealt with (including the updated A-status) with a save on its private MOC.
When, in the previous test body, I need to invoke the very same algorithm again on the very same entity A after having updated some of its fields in order to test the new algorithm outcome, I need to put A's date field back to Nil before invoking the algorithm. This is what I do:
A.date_field = Nil;
[[TestCoreDataManager sharedInstance] save];
// <invoke_algorithm>
(TestCoreDataManager is a further singleton providing objects and saving them by means of the previously reported function). The problem is that when the algorithm retrieves again the object, the date_field is not Nil but still contains the previously assigned value.
It seems like the instance of A retrieved by the algorithm in its private context is not up-to-date wrt the underlying persistent store. Is there anyone who might tell me what I'm doing wrong?
Some more details
I've just moved the default semantics of this date field in order to be always not nil and to have 0 as default value. I rewrote the algorithm in order for the test condition to be [A.date_field timeIntervalSince1970] == 0 in place of A.date_field == Nil.
In my code, in order for that test to be met, I use the following code
A.date_field = [NSDate dateWithTimeIntervalSince1970:0];
[TestCoreDataManager save]; // [mainManagedObjectContext saveOnPersistentStore:&myError];
// Get a Local Managed Object Context
NSManagedObjectContext* myLocalMOC =
[[DDRestKitManager sharedInstance].objectManager.managedObjectStore
newChildManagedObjectContextWithConcurrencyType:NSPrivateQueueConcurrencyType
tracksChanges:YES];
<query_for_A_entities_in_the_store>;
At this point A.date_field contains the value it had before resetting to 0 seconds from 1970.
The even more strange part follows. If I replace
A.date_field = [NSDate dateWithTimeIntervalSince1970:0];
with
A.date_field = [NSDate dateWithTimeIntervalSince1970:1];
or
A.date_field = [NSDate dateWithTimeIntervalSince1970:-1];
and leave the rest of the code untouched, then the child managed object context fetch an A object with the date_field now up-to-date to the correct date and time (1970, 1:00:01 a.m. or 0:59:59 a.m. respectively).
This is driving me crazy.
I have a member named _label as an ivar member in class :
#interface CCHelloWorldLayer : CCLayer
{
CCLabelBMFont *_label;
}
in another codeblock: initializing with this line:
_label = [CCLabelBMFont labelWithString:#"Testing " fntFile:fntName];
question is this:
if I want to modify its text what Should I do ?
I dont see any method like:
[_label setString:#"Well.there is no such a method"];
if I do
_label = [CCLabelBMFont labelWithString:#"Testing " fntFile:fntName];
_label = [CCLabelBMFont labelWithString:#"Well.there is no such a method"
fntFile:fntName];
is first memory allocation autoreleasing it self ?
is it safe to recall labelWithString method repeately ?
(note:I dont use ARC in test project.and I wont.)
thanks in advice
There is a setString method but it appears to be "private". The +labelWithString method does create an autorelease object and can be used repeatedly. It looks like it creates a texture, so you would want to create a new texture each time (as opposed to trying to modify it).
In general though, if you want the autoreleased object to stick around, you should retain it and release it when you're done.
[_label setString:#"Well.there is no such a method"];
This method exists and you can call it like that. Try it, it works.
The method is not declared in the class but in CCLabelProtocol.
I am writing a COM Server which have a plenty of Interfaces and methods. And most of the methods have the BSTR as the parameters and as local parameters used for the return. A snippet looks like
Update 5:
The real code. This fetches from bunch of Data based on a specific condition the DB to populate an array of Object.
STDMETHODIMP CApplication::GetAllAddressByName(BSTR bstrParamName, VARIANT *vAdddresses)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState())
//check the Database server connection
COleSafeArray saAddress;
HRESULT hr;
// Prepare the SQL Strings dan Query the DB
long lRecCount = table.GetRecordCount();
if (lRecCount > 0)
{
//create one dimension safe array for putting details
saAddress.CreateOneDim(VT_DISPATCH,lRecCount);
IAddress *pIAddress = NULL;
//retrieve details
for(long iRet = table.MoveFirst(),iCount=0; !iRet; iRet = table.MoveNext(),iCount++)
{
CComObject<CAddress> *pAddress;
hr = CComObject<CAddress>::CreateInstance(&pAddress);
if (SUCCEEDED(hr))
{
BSTR bstrStreet = ::SysAllocString(table.m_pRecordData->Street);
pAddress->put_StreetName(bstrStreet);
BSTR bstrCity = ::SysAllocString(table.m_pRecordData->City);
pAddress->put_CityName(bstrCity);
}
hr = pAddress->QueryInterface(IID_IAddress, (void**)&pIAddress);
if(SUCCEEDED(hr))
{
saAddress.PutElement(&iCount,pIAddress);
}
}
*vAdddresses=saAddress.Detach();
}
table.Close();
return S_OK;
}
STDMETHODIMP CAddress::put_CityName(BSTR bstrCityName)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState())
// m_sCityName is of CComBSTR Type
m_sCityName.Empty();//free the old string
m_sCityName = ::SysAllocString(bstrCityName);//create the memory for the new string
return S_OK;
}
The problem lies in the Memory Freeing part. The code works very fine in any Win XP machines, but when comes to WIN2K8 R2 and WIN7 the code crashes and pointing to the ::SysFreeString() as the culprit. The MSDN is not adequate to the solution.
Can anyone please help in finding the right solution?
Thanks a lot in advance :)
Update 1:
I have tried using the CComBSTR as per the suggestion in the place of raw BSTR, initialized using direct CString's and excluded the SysFreeString(). But for my trouble, on getting out of scope the system is calling the SysFreeString() which again causes the crash :(
Update 2:
With the same CComBSTR i tried to allocate using the SysAllocString() , the problem remains same :(
Update 3:
I am tired of all the options and in peace I am having only question in mind
Is it necessary to free the BSTR through SysFreeString() which was
allocated using SysAllocString()/string.AllocSysString()?
Update 4:
I missed to provide the information about the crash. When I tried to debug the COM server crashed with a error saying
"Possible Heap Corruption"
. Please help me out of here.. :(
// Now All Things are packed in to the Object
obj.Name = bstrName;
obj.Name2 = bstrname2;
I don't quite understand what do you mean by saying that things are packed since you're just copying pointers to the strings, and at the moment when you call SysFreeString obj.Name and obj.Name2 will point to an invalid block of memory. Although this code is not safe, it looks like if the source of your problem is class CFoo. You should show us more details of your code
I suggest you to use a CComBSTR class which will take a responsibility for releasing the memory.
UPDATE
#include <atlbase.h>
using namespace ATL;
...
{
CComBSTR bstrname(_T("Some Name"));
CComBSTR bstrname2(_T("Another Name"));
// Here one may work with these variables if needed
...
// Copy the local values to the Obj's member Variable
bstrname.Copy(&obj.Name);
bstrname2.Copy(&obj.Name2);
}
UPDATE2
First of all one should free bstrCity and bstrStreetName with SysFreeString or use CComBSTR instead within this block:
if (SUCCEEDED(hr))
{
BSTR bstrStreet = ::SysAllocString(table.m_pRecordData->Street);
pAddress->put_StreetName(bstrStreet);
BSTR bstrCity = ::SysAllocString(table.m_pRecordData->City);
pAddress->put_CityName(bstrCity);
// SysFreeString(bstrStreet)
// SysFreeString(bstrCity)
}
Consider to amplify the loop's condition !iRet with iCount < lRecCount.
for(...; !iRet /* && (iCount < lRecCount) */; ...)
Also, here:
m_sCityName = ::SysAllocString(bstrCityName);
you allocate memory but never release it since internally CComBSTR& operator = (OLESTR ..) allocates a new storage itself. One should rewrite is as follows:
m_sCityName = bstrCityName;
Everything else, looks good for me
UPDATE3
Well, Heap corruption is often a consequence of writing some values outside of the allocated memory block. Say you allocate an array of length 5 and put some value to the 6th position
Finally I have found the real reason for the Heap Corruption that happened in the code.
The put_StreetName/put_CityName of the IAddress/CAddress is designed in a following way.
STDMETHODIMP CAddress::put_CityName(BSTR bstrCityName)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState())
m_sCityName.Empty();
TrimBSTR(bstrCityName);
m_sCityName = ::SysAllocString(bstrCityName);
return S_OK;
}
BSTR CAddress::TrimBSTR(BSTR bstrString)
{
CString sTmpStr(bstrString);
sTmpStr.TrimLeft();
sTmpStr.TrimRight();
SysReAllocString(&bstrString,sTmpStr); // The Devilish Line
}
The Devilish Line of code is the real culprit that caused the Memory to go hell.
What caused the trouble?
In this line of code, the BSTR string passed as a parameter is from another application and the real memory is in another realm. So the system is trying to reallocate teh string. Either succeed or not, the same is tried to cleared off from the memory in original application/realm, thus causing a crash.
What still unsolved?
Why the same piece of code doesn't crashed a single time in Win XP and
older systems? :(
Thanks for all who took their time to answer and solve my problem :)
I have a weird problem with FetchRequest template.
When i explicitly hardcode the variable I wish to substitute:
NSFetchRequest *fetchRequest = [[[Helper appDelegate] managedObjectModel]
fetchRequestFromTemplateWithName:#"srStoryForLesson"
substitutionVariables:[NSDictionary dictionaryWithObject:[NSNumber numberWithInt:2] forKey:#"number"]];
Every thing works fine.
But When I try to set a var as the Integer (as i want it to be dynamic) I get no results from the fetch.
NSInteger number = 2;
NSFetchRequest *fetchRequest = [[[Helper appDelegate] managedObjectModel]
fetchRequestFromTemplateWithName:#"srStoryForLesson"
substitutionVariables:[NSDictionary dictionaryWithObject:[NSNumber numberWithInt:number] forKey:#"number"]];
I can not understand what is wrong?
Thanks
Shani
The code you show should work fine. Your error is elsewhere.
I would recommend not using variable names like "number" because their generic nature risk naming collisions in Objective-C's global name space. A more unique and descriptive name is safer and easier to read months down the road when you revisit the code.