Object allocated without autorelease keyword inside autoreleasepool. What happens? - automatic-ref-counting

#autoreleasepool {
MyObject *tempObj = [[MyObject alloc] init]; // no autorelease mentioned here
}
Once the control is out of previous block, does tempObj get released? Even though I have not added autorelease? Why?

Related

useLayoutToLayoutNavigationTransitions in iOS7 crash

I am building an iOS7 app and I am trying to make use of the new useLayoutToLayoutNavigationTransitions effect. I have 2 UICollectionViewControllers and when I do the following I get the transition effect
SecondViewController *secondVC = [[SecondViewController alloc] initWithNibName:#"SecondViewController" bundle:nil];
secondVC.useLayoutToLayoutNavigationTransitions = YES;
[self.navigationController pushViewController:secondVC animated:YES];
this works fine but what I want to do is make an api call and then in the completion block I want to push onto the nav stack like so
[webAPI getDetailsWithParams:params andCompletionBlock:^(id dict) {
//some work on the result
SecondViewController *secondVC = [[SecondViewController alloc] initWithNibName:#"SecondViewController" bundle:nil];
secondVC.useLayoutToLayoutNavigationTransitions = YES;
[self.navigationController pushViewController:secondVC animated:YES];
} andErrorBlock:^(NSError *error) {
}];
but this crashes every time with the following msg
-[UICollectionView _invalidateLayoutWithContext:]: message sent to deallocated instance 0x17a26400
can anyone tell me what I am doing wrong in this case? How can I get the transition effect when pushing from completion block?
EDIT: by changing it to the following I was able to transition to the second viewcontroller.
MyLayout *layout = [[MyLayout alloc] init];
SecondViewController *expandedVC = [[SecondViewController alloc] initWithCollectionViewLayout:layout];
and I also deleted the nib file that went with the file. nib file just consisted of a collection view and it was the file owners view.
While I can now transition I still do not understand why I could not do the previous nib method with in a block. So I would be grateful if someone could shed some light on it for me.
In order to use UICollectionViewController's useLayoutToLayoutNavigationTransitions to make transitions, the layout of the SecondViewController must be known. However, if you use initWithNibName:bundle: initializer, layout is not internally prepared yet, making your desired transitions impossible. As you mentioned in your edited question, you have to use [UICollectionViewController initWithCollectionViewLayout:] to initialize your second UICollectionViewController. Since your xib file has the same name as your class name, SecondViewController.xib is going to be loaded automatically by UIViewController, superclass of UICollectionViewController.
I think you were making UIKit calls from a thread that wasn't the main thread

Can not create NSError: unrecognized selector

I am trying to create a NSError category to make pre-defined errors based upon status codes. However, any time that I try to create a NSError from my category, I get a
+[NSError errorWithDomain:code:userInfo:]: unrecognized selector sent to class 0x2b2b20
I have also tried calling the instance version of the NSError Initializer but this has the same result.
+(NSError*)errorOfType:(ErrorType)errorType inClassNamed:(NSString*)_nsClassName andMessage:(NSString*)_nsMessage
{
return [[[self class] alloc]initWithType:errorType inClassNamed: _nsClassName andMessage:_nsMessage];
}
#pragma mark -
#pragma mark - Init
-(id)initWithType:(ErrorType)errorType inClassNamed:(NSString*)_nsClassName andMessage:(NSString*)_nsMessage
{
NSInteger _nCode = [self codeFromErrorType:errorType];
NSDictionary *_nsUserInfo = [self localizedDescriptionForErrorType:errorType andMessage:_nsMessage];
NSLog(#"Why Does this fail? Is this Nil? %#, \n%i, \n%#", _nsClassName, _nCode, _nsUserInfo);
if ([self respondsToSelector:#selector(initWithDomain:code:userInfo:)]) {
if (self = [self initWithDomain:_nsClassName code:_nCode userInfo:_nsUserInfo]){
}
}else{
NSLog(#"NSERROR Did not create!!!");
}
return self;
}
When I run this code calling the static method, The output is:
2013-05-10 17:46:18.851 BMPassSDK-DemoApp[99692:c07] Why Does this fail? Is this Nil? Domain,
107,
{
NSLocalizedDescription = "A connection to the server could not be made. Please Try again later. ";
}
2013-05-10 17:46:18.851 BMPassSDK-DemoApp[99692:c07] NSERROR Did not create!!!
2013-05-10 17:46:18.852 BMPassSDK-DemoApp[99692:c07] +[NSError errorWithDomain:code:userInfo:]: unrecognized selector sent to class 0x2b2b20
(lldb) po 0x2b2b20
$0 = 2829088 NSError
(lldb)
Anyone have any suggestions on what I am missing?
When I first made this class it was a subclass of NSError. Later, when I tried to convert it from a subclass to category, I accidentally renamed my header file's base class to type NSObject instead of NSError. This is of course what was causing my issue because NSObjects do not respond to the selector initWithDomain:code:userInfo.
Anyways, thanks everyone for looking. Hope it helps someone else.

Why does OCMock cause nsnotificaiton center to have EXC_BAD_ACCESS when using mockObserver

I setup mock observers like this:
id quartileObserverMock = [OCMockObject observerMock];
[[NSNotificationCenter defaultCenter] addMockObserver:quartileObserverMock
name:kVPAdPlayerDidReachQuartileNotification
object:self.adPlayer];
[[quartileObserverMock expect]
notificationWithName:kVPAdPlayerDidReachQuartileNotification
object:self.adPlayer
userInfo:#{#"quartile" : #(VPAdPlayerFirstQuartile), #"trackingEvent" : VPCreativeTrackingEventFirstQuartile}];
my unit tests run; but I get spurious EXC_BAD_ACCESS errors when the notificaiton is posted.
i.e.
[[NSNotificationCenter defaultCenter]
postNotificationName:kVPAdPlayerDidReachQuartileNotification
object:self.adPlayer
userInfo:#{#"quartile" : #(quartile), #"trackingEvent" : trackingEvent}];
When I comment out the observermock code my tests run fine every single time.
When I put the code back in, I get spurious crashes on postNotiicaitonName:object:userInfo, maybe once every 2.5 times.
Anyone got any ideas?
Refer the following sample code, this might help you. It worked for me
- (void)test__postNotificationwithName__withUserInfo
{
id observerMock = [OCMockObject observerMock];
[[NSNotificationCenter defaultCenter] addMockObserver:observerMock name:#"NewNotification" object:nil];
NSDictionary *userInfo = [[NSDictionary alloc] initWithObjectsAndKeys:#"2",#"2", nil];
[[observerMock expect] notificationWithName:#"NewNotification" object:[OCMArg any] userInfo:userInfo];
NotificationClass *sut = [[NotificationClass alloc] init];
[sut postNotificationwithName:#"NewNotification" userInfo:userInfo];
[[NSNotificationCenter defaultCenter] removeObserver:observerMock];
[observerMock verify];
}
and my posting notification method
- (void)postNotificationwithName:(NSString *)notifName userInfo:(NSDictionary *)userInfo
{
[[NSNotificationCenter defaultCenter] postNotificationName:notifName object:self userInfo:userInfo];
}
Please note:
observerMock always raise an exception when an unexpected notification is received.
Remove the mocked observer from the NSNotificationCenter at the end of the test case.
There are a couple of reasons why this could be happening (I know, because I just solved both of them them in my own code today)
1) A mock observer from a previous test was not removed
2) An non-mock instance object from a previous test is observing for the same notification, but that object has since become obsolete. In my case, an instance object from my setUp method was listening to the notification, but when it was dealloced, it did not remove itself from the NSNotificationCenter's observers list.
In both cases the solution is to use
[[NSNotificationCenter defaultCenter] removeObserver:name:object:]
Depending on the scope: 1) in the dealloc of all classes that observe NSNotificationCenter, 2) in the tearDown method, or 3) at the end of the test case (as #PrasadDevadiga mentioned)

Add NSString to NSMutableArray if NSString is not already pressent - not working

Can't understand why this won't work, it simply says id num hasn't been used before every time... and never adds it to the array. Any help on this would be much appreciated. I'm almost certainly missing something obvious, but its driving me mad.
- (IBAction)idNumInputEnd:(id)sender
{
// Check if ID Number has been used before, if it hasnt, add it to the list.
NSString *idNumCheck = idNumberInput.text;
if ([idNumberList containsObject:idNumCheck])
{
NSLog(#"This id number has been used before, ask user if he would like to reload the data");
}
else
{
NSLog(#"This id number hasn't been used before and is thus being added to the array");
[idNumberList addObject:idNumCheck];
}
}
My suspect (shared by Martin, as per his comment) that idNumberList has never been allocated and initialized to an empty NSMutableArray.
If that's the case ARC will assign nil to idNumberList, therefore [idNumberList containsObject:idNumCheck] will evaluate to nil, as well as [idNumberList addObject:idNumCheck]
In other terms your evaluated code becomes something like
if (nil) {
NSLog(#"This id number has been used before, ask user if he would like to reload the data");
} else {
NSLog(#"This id number hasn't been used before and is thus being added to the array");
nil;
}
Given that, the else branch will always be taken, the addObject call to a nil object will fail silently and this causes the behavior you're experiencing.
To fix that, initialize idNumberList like follows:
idNumberList = [[NSMutableArray alloc] init];

cellForRowAtIndexPath: returns nil for a generic prototype cell

This is driving me nuts!
I have a generic UITableViewController class with a generic prototype cell, with an identifier "myCell". Developing under ARC, iOS5 and using Storyboard, I am using the following method:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"myCell"];
cell.textLabel.text = #"Title";
return cell;
}
Everything is hooked up in the storyboard, file owner, etc. I have several other UITableViewController in my project, using the same concept. All are working.
This particular class of UITableViewController doesn't want to work! keep throwing me the exception:
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'UITableView dataSource must return a cell from tableView:cellForRowAtIndexPath:'
Nslog'ed --> [tableView dequeueReusableCellWithIdentifier:#"myCell"] = (null)
Any idea and help is greatly appreciated!
EDIT:
For simplicity:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return 1;
}
Things that I have already done:
1. delete and create and set up the UITableViewController in storyboard!
2. Restarted Xcode
3. Restarted simulator
4. Restarted computer!!!!
5. Deleted and built the app over and over!
None worked.
By the way, I tried
if (cell == nil)
cell = [UITableViewCell alloc] initWithStyle....
.. and it will solve the problem, but again... this is ARC, storyboard, ... I am not supposed to do that. Xcode is supposed to take care of it!
You have to create your cell:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"myCell"];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"myCell"] autorelease];
}
cell.textLabel.text = #"Title";
return cell;
}
Eventually I found the bug. I can't say I found the root cause, but investigating line by line, this is what I found and worked for me.
I have some objects in my UITableViewController that need to be alloc/init'ed before the view gets loaded, so that when callers can set them to pre-determind values. Since viewDidLoad is too late, I put them in initWithCoder method.
Commeting out and re-writing the initwithCoder method solved the problem. It seemed to me, that initWithCoder method was initing the UITableViewController as some different!
I had the same problem and just managed to overcome it.
If you are creating cells data dynamically you have to do the following things:
Select the table view.
Then go to the object inspector to the third tab from the right.
The first option is named: "Content". Change the selection from "Static Cells" to "Dynamic Prototypes".
Make sure you set the identifier of the cell properly and it is the same name you use on the "dequeueResableCellWithIdentifier"
It worked for me. I stopped getting "nil" cell values and everything seems to work properly.
if the "IF" statement is falling to true (cell == nil) for the following:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"myCell"];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"myCell"] autorelease];
}
cell.textLabel.text = #"Title";
return cell;
}
then the name #"myCell" was either misspelled (Doesn't match) or is missing from the storyboard identifier field for the cell.

Resources