我对ARC如何工作有点困惑,我知道有自动引用计数但是这个功能甚至可以用于分配原始实例变量(不使用属性).
例如,如果我有一个实例变量arr:
@interface TestClass : NSObject {
NSArray *arr;
}
Run Code Online (Sandbox Code Playgroud)
现在如果在方法内部我使用自动释放分配它NSArray:
- (IBAction)test {
arr = [NSArray arrayWithObject:@"TEST"];
}
Run Code Online (Sandbox Code Playgroud)
这个阵列会发生什么?是否只是神奇地保留它,直到arr被重新分配给其他东西?
现在,如果我做了类似的事情:
self.arr = [NSArray arrayWithObject:@"TEST"];
Run Code Online (Sandbox Code Playgroud)
如果它强而弱,会发生什么?
Apple最近发布了Transitioning to ARC Release Notes,这是一份解释ARC的文档,解决了将非ARC代码转换为ARC的一些问题.在这些说明中,他们提到了以下内容:
如果您[原文如此]发现必须实现自定义保留或释放方法,那么您还必须在类中实现以下方法:
Run Code Online (Sandbox Code Playgroud)-(BOOL)supportsWeakPointers { return NO; }此方法将防止弱对象形成到您的对象.强烈建议您找到一种不需要实现自己的保留和释放方法而不是这样做的解决方案.
考虑这种情况:
声明一个名为MyClass的类,并将-supportsWeakPointers实现为返回NO.告诉Xcode使用-fno-objc-arc编译相应的实现文件.为了更好地衡量,请将类声明为NS_AUTOMATED_REFCOUNT_WEAK_UNAVAILABLE并覆盖-release和-retain.
在MainMenu.xib中,放置一个MyClass类型的顶级对象.
在应用程序委托中,为MyClass的实例指定弱IBOutlet属性:
@property (weak) IBOutlet MyClass *myObject;
Run Code Online (Sandbox Code Playgroud)
并将其连接到nib文件中的相应对象.在这种情况下,由于对象是顶级nib对象而File的Owner属于NSApplication类型,因此该对象是使用额外的引用计数创建的,这意味着它应该保持活动直到显式释放.使用ARC,这意味着调用CFRelease(),因为ARC禁止发送释放消息.
我的问题是双重的三倍:
为什么是-supportsWeakPointers实例方法而不是类方法?是否存在类允许弱引用的实例不同的情况?
-supportsWeakPointers永远不会发送到加载nib文件时创建的MyClass实例; 为什么?我已经通过在其中放置NSLog()并向Xcode添加符号断点来测试它.而且,我从来没有得到过
cannot form weak reference to instance (0x???) of class MyClass
Run Code Online (Sandbox Code Playgroud)
我运行程序时的消息.
在程序执行期间,MyClass类型的顶级nib对象永远不会被释放,因为我的程序永远不会释放它.但是,在加载nib文件后,相应的弱插座为nil; 为什么?将outlet属性更改为strong会导致对象与nil不同,但这不是必需的.真的不会发生; 抱歉.我正在测试一个版本,该版本正在分配一个尚未真正使用的新对象,因此ARC正确分配nil给该属性.
我在Mac OS X v10.7.2盒子上使用Xcode 4.2和Apple LLVM Compiler 3.0.
我有一个MKMapView,我正在添加这样的注释:
for (NSDictionary *tmp in response)
{
NSDictionary *places = [tmp objectForKey:@"place"];
NSDictionary *location = [places objectForKey:@"location"];
NSLog(@"long: %@ Lat:%@",[location objectForKey:@"longitude"], [location objectForKey:@"latitude"]);
float longitude = [[location objectForKey:@"longitude"] floatValue];
float latitude = [[location objectForKey:@"latitude"] floatValue];
CLLocationCoordinate2D locationco = {latitude,longitude};
NSString *titleString = [tmp objectForKey:@"name"];
Place *pin = [[Place alloc] init];
pin.coordinate = locationco;
pin.title = titleString;
pin.subtitle = @"A Location";
//NSArray *annots = [[NSArray alloc] initWithObjects:pin, nil];
//[map addAnnotations:annots];
[map addAnnotation:pin];
[[map viewForAnnotation:pin] setCanShowCallout:YES];
}
Run Code Online (Sandbox Code Playgroud)
本MKAnnotation的显示在地图上罚款,我可以选择它们,但是没有出现标注泡沫.我知道他们正在被选中 …
编辑:改变了标题.我当时不知道它,但这是一个重复的为什么我崩溃MKMapView释放后,如果我不再使用它?
这个问题类似于为什么在使用ARC + NSZombieEnabled时对象没有dealloc'ed,但足够不同以至于我认为值得抛弃,以防任何人理解并可以向我解释发生了什么.另一个问题可能是XCode错误,所以我认为这可能是类似的.
场景:
RootViewController有tableView一堆显示项目detailViewController包含另一个单元格的模态tableViewdetailViewController包含MKMapView显示项目的位置mapView.delegate = detailViewControllerdetailViewController在此之后不久,应用程序崩溃b/c MKMapView发送mapView:viewForAnnotation:到现在dealloc'ed detailViewController.此崩溃在具有临时分发构建的用户设备上重新编写,因此该问题与此无关NSZombieEnabled.
我能够通过添加以下内容来解决崩溃:
_mapView.delegate = nil;
Run Code Online (Sandbox Code Playgroud)
到包含mapView 的dealloc方法tableViewCell.
问题:为什么有必要在细胞被解除分配时使代表无效?mapView当细胞被解除分离时,似乎应该由ARC解除分离,这样就不必要了.没有代表是好的做法,但我认为在这种情况下不需要.
编辑:两者的所有子视图detailViewController和UITableViewCells声明(nonatomic, strong)属性ala:
@property (nonatomic, strong) MKMapView * mapView;
Run Code Online (Sandbox Code Playgroud)
编辑2:猜猜我需要更好地阅读文档.@fluchtpunkt是对的.以下是MKMapView文档中的相关信息:
在释放已设置委托的MKMapView对象之前,请记住将该对象的委托属性设置为nil.您可以在dealloc方法中处理地图视图.
ARC迁移工具在开始迁移之前拒绝接受此代码:
[self.delegate performSelector:@selector(overlayDismissed:) withObject:self afterDelay:0];
Run Code Online (Sandbox Code Playgroud)
委托被迫使用协议实现此方法,它应该工作正常:
@protocol OverlayDelegate <NSObject>
- (void)overlayDismissed:(Overlay*)overlay;
@end
@interface Overlay : UIImageView {
id<OverlayDelegate> delegate;
}
@property (nonatomic, assign) id<OverlayDelegate> delegate;
Run Code Online (Sandbox Code Playgroud)
ARC有什么问题?为什么它告诉我"没有已知的选择器实例方法'performSelector:withObject:afterDelay:'?
我已在"摘要"部分阅读过渡到ARC发行说明.他们告诉:
ARC的工作原理是在编译时添加代码,以确保对象在必要时生效,但不再生效.从概念上讲,它通过为您添加适当的内存管理调用,遵循与手动引用计数(在高级内存管理编程指南中描述)相同的内存管理约定.
为了让编译器生成正确的代码
我想知道ARC纠正我们代码的结果.
我的问题:我们能看到变化吗?(在分配,保留,分配或释放的期限.不是组装级别!)
原因:因为我认为在没有ARC模式的情况下,在旧的传统开发中看到最佳实践代码是很好的.
现在我已升级到Lion和Xcode 4.3.x,调试器正在进入ARC的东西.所以我看到一个充满了屏幕
libobjc.A.dylib`objc_retainAutoreleasedReturnValue:
0x1de7fe0: pushl %ebp
Run Code Online (Sandbox Code Playgroud)
和pushl和movl和subl等可惜我不能symbolicate这些,我也不关心调试苹果的东西.有没有办法让调试器只关注我实际拥有的代码?
我正在使用LLDB,但GDB也是如此.
编辑:这也发生在AppCode上,它说了些什么(但我不知道是什么).
我有一个自定义容器UIViewController,它有六个子UIViewControllers,以及一组用户与之交互以在子视图控制器之间切换的选项卡.问题是当我的容器视图控制器被释放时,子视图控制器不是.
我已经验证通过向dealloc方法添加一些调试代码而不释放子视图控制器,只要它们的视图没有添加到容器视图控制器的视图中,它们就会被释放.
下面是我用来创建自定义容器视图控制器的代码的摘录.viewController指针是iVars.我也在使用ARC,这就是为什么没有实际的发布调用.
- (void)init
{
if ((self = [super init])) {
vc1 = [[UIViewController alloc] init];
[self addChildViewController:vc1];
vc2 = [[UIViewController alloc] init];
[self addChildViewController:vc2];
vc3 = [[UIViewController alloc] init];
[self addChildViewController:vc3];
vc4 = [[UIViewController alloc] init];
[self addChildViewController:vc4];
vc5 = [[UIViewController alloc] init];
[self addChildViewController:vc5];
vc6 = [[UIViewController alloc] init];
[self addChildViewController:vc6];
}
return self;
}
- (void)dealloc
{
[vc1 removeFromParentViewController];
vc1 = nil;
[vc2 removeFromParentViewController];
vc2 = nil;
[vc3 removeFromParentViewController];
vc3 = nil;
[vc4 removeFromParentViewController];
vc4 = …Run Code Online (Sandbox Code Playgroud) 从较大的一部分创建了一个非常简单(单一视图)的示例项目.它适用于iOS SDK 8.3.
当您点击"显示我"按钮时,视频会出现(作为模态),2秒后,它会消失.看起来不错.但不久之后,应用程序崩溃了,因为-dealloc消息被发送到已经解除分配的对象.
[MPAVController release]:发送给deallocated实例的消息
这是我的示例项目(不要忘记Video.mp4):
ViewController.h
#import <UIKit/UIKit.h>
@interface ViewController : UIViewController
@end
Run Code Online (Sandbox Code Playgroud)
ViewController.m
#import "ViewController.h"
#import "MediaViewController.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
UIButton *button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[button setTitle:@"Show me!" forState:UIControlStateNormal];
button.frame = CGRectMake(10.0, 10.0, 100.0, 30.0);
[button addTarget:self action:@selector(buttonTapped:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:button];
}
- (void)buttonTapped:(id)sender
{
MediaViewController *mediaVC = [[MediaViewController alloc] initWithNibName:nil bundle:nil];
[self presentViewController:mediaVC animated:YES completion:^{
[self performSelector:@selector(dismissPresentedController) withObject:nil afterDelay:2.0];
}];
}
- (void)dismissPresentedController
{
[self.presentedViewController dismissViewControllerAnimated:YES completion:nil]; …Run Code Online (Sandbox Code Playgroud) 我已经编程Swift了几个月了.最近,我更多地关注Swift语言如何运作的概念.
因此,最近在阅读关于自动引用计数(ARC)的Apple文档时,我遇到了以下几行:
这一个在上面:
在大多数情况下,这意味着内存管理在Swift中"正常工作",您不需要自己考虑内存管理.当不再需要这些实例时,ARC会自动释放类实例使用的内存.
在下一段中,以下内容如下:
为了实现这一点,无论何时将类实例分配给属性,常量或变量,该属性,常量或变量都会对实例进行强引用.该引用被称为"强"引用,因为它保持对该实例的坚定持有,并且只要该强引用仍然存在就不允许它被释放.
我对这种情况的动态有点困惑.我在使用故事板时注意到,你设置了对弱的引用,因此类看起来像这样,我也称之为案例1:
情况1
class SomeClass : UIViewController {
@IBOutlet weak var nameLabel : UILabel!
override func viewDidLoad() {
nameLabel.text = "something."
}
}
Run Code Online (Sandbox Code Playgroud)
这里,标签与ViewController有一对一的弱引用,一旦Controller被更改,引用就会被破坏(内存dealloc),因为它很弱.因此,没有与内存有关的问题.
如果上述陈述错误或松散,请原谅我.如果有人确认我的假设或反击它,我会很高兴.
我的问题是关于第二种情况,我不使用故事板和类如下所示:
案例2
class SomeClass : UIViewController {
var nameLabel : UILabel = {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
override func viewDidLoad() {
view.addSubView(nameLabel)
// view.addConstraints...
}
}
Run Code Online (Sandbox Code Playgroud)
对于上面的情况,我的假设是ViewController与标签有一对一的强引用,ViewController中的视图也有标签的强引用..如果类被更改/标签从子视图中删除..那么我认为记忆不会被解除分配.或者至少视图控制器将保持对标签的强引用(根据文档).
我通过从视图的子视图中删除标签并打印出标签来确认这一点(它给了我一个UILabel的实例,其框架为0原点和0大小.)因此一个实例不是零.
我唯一可以从中收集到的是,尽管标签已从UIView中删除,但它仍然保持与控制器的强引用,因此在内存中保持永久状态.我对吗?
如果是这样的话.我应该如何防止我的代码出现此类内存问题?更大的问题是,如果我像这样声明我的变量,我将它添加为nil,同时将其添加为控制器中主视图的子视图.
weak var nameLabel : UILabel = {
let …Run Code Online (Sandbox Code Playgroud)